home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 2
/
Atari Mega Archive CD - Volume 2.iso
/
linux
/
src
/
lnx09p4.dgz
/
linux-0.9pl4.diffs
Wrap
Text File
|
1994-11-24
|
430KB
|
14,397 lines
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/MakeVars linux-0.9pl4/MakeVars
--- linux-0.9pl3/MakeVars Sun Aug 14 10:30:54 1994
+++ linux-0.9pl4/MakeVars Mon Nov 21 18:08:53 1994
@@ -20,7 +20,7 @@
ASINCS = $(INCFLAGS) -O2
HOSTINCFLAGS = -Dlinux
HOSTFLAGS = -O2 -Wall $(HOSTINCFLAGS)
-LDFLAGS =
+LDFLAGS = -qmagic -Ttext 0xC0000FE0
AR = ar
RANLIB = ranlib
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/Makefile linux-0.9pl4/Makefile
--- linux-0.9pl3/Makefile Tue Sep 27 22:18:26 1994
+++ linux-0.9pl4/Makefile Mon Nov 21 18:08:53 1994
@@ -1,6 +1,6 @@
-# Makefile for Amiga Linux main source directory
+# Makefile for Linux/68k main source directory
#
-# Copyright 1993 by Hamish Macdonald
+# Copyright 1993,1994 by Hamish Macdonald
#
# This file is subject to the terms and conditions of the GNU General Public
# License. See the file "README.legal" in the main directory of this archive
@@ -8,7 +8,7 @@
VERSION = 0
PATCHLEVEL = 9
-SUBLEVEL = 3
+SUBLEVEL = 4
all: Version vmlinux
@@ -76,13 +76,13 @@
endif
ifdef CONFIG_AMIGA
-AMIGA_BOOTOBJS := tools/amiga/bootstrap.o tools/amiga/get_nlist.o
+AMIGA_BOOTOBJS := tools/amiga/bootstrap.o
ARCHIVES := $(ARCHIVES) amiga/amiga.o
SUBDIRS := $(SUBDIRS) amiga
endif
ifdef CONFIG_ATARI
-ATARI_BOOTOBJS := tools/atari/bootstrap.o tools/atari/get_nlist.o
+ATARI_BOOTOBJS := tools/atari/bootstrap.o
ARCHIVES := $(ARCHIVES) atari/atari.o
SUBDIRS := $(SUBDIRS) atari
endif
@@ -145,7 +145,7 @@
$(CC) $(CFLAGS) -c -o $*.o $<
vmlinux: m68k/head.o init/main.o init/config.o tools/version.o linuxsubdirs
- $(LD) $(LDFLAGS) -T 0xC0000000 -M m68k/head.o init/main.o init/config.o \
+ $(LD) $(LDFLAGS) -M m68k/head.o init/main.o init/config.o \
tools/version.o \
$(ARCHIVES) \
$(FILESYSTEMS) \
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/amiga/amicon.c linux-0.9pl4/amiga/amicon.c
--- linux-0.9pl3/amiga/amicon.c Sun Aug 14 10:29:40 1994
+++ linux-0.9pl4/amiga/amicon.c Thu Nov 10 17:56:32 1994
@@ -1079,8 +1079,6 @@
char *this_opt;
int i;
- printk ("video_setup: options are %s\n", options);
-
if (!options || !*options) {
return;
}
@@ -1102,13 +1100,17 @@
}
}
-static long amicon_init(struct condata *conp, long kmem_start)
+static long amicon_init(struct condata *conp, long kmem_start, char**display_desc)
{
int unit = conp - vc_cons;
register struct display *p = &disp[unit];
int mode = amicon_mode;
int inverse_video = amicon_inverse;
ulong model;
+ static int master_init = 0;
+
+ if(master_init==0)
+ {
model = boot_info.bi_un.bi_ami.model;
@@ -1128,14 +1130,29 @@
}
}
+ *display_desc = modes[mode].modename;
init_vblank();
+
display_init(p, &modes[mode], inverse_video);
+ }
+ else
+ {
+ /* Copy all from the first console, maybe allow different
+ display modes later. */
+ disp[unit] = disp[0];
+ }
- conp->vc_cols = p->scr_width / p->fontwidth;
- conp->vc_rows = p->scr_height / p->fontheight;
+ conp->vc_cols = disp[unit].scr_width / disp[unit].fontwidth;
+ conp->vc_rows = disp[unit].scr_height / disp[unit].fontheight;
+ conp->vc_can_do_color = 0;
+ conp->vc_flags |= CON_INITED;
+ if(master_init==0)
+ {
if(!mach_add_isr(IRQ_AMIGA_VERTB, (isrfunc)amicon_interrupt, 0, NULL))
panic("Couldn't add vblank interrupt");
+ master_init=1;
+ }
#ifdef DEBUG
printk("amicon_init: fired up mode %s\n", modes[mode].modename);
@@ -1147,6 +1164,17 @@
static int amicon_deinit (struct condata *conp)
{
+ struct display *p = &disp[conp - vc_cons];
+ static int amicon_switch (struct condata *conp);
+
+ /* You can't deinit a non inited screen nor the console 0. */
+ if (!(conp->vc_flags & CON_INITED) || p == disp)
+ return -1;
+
+ amicon_switch (&vc_cons[0]); /* Always switch to the console 0 */
+ memset (p, 0, sizeof (struct display));
+ conp->vc_flags &= ~CON_INITED;
+
return 0;
}
@@ -1389,9 +1417,11 @@
int sy, int sx, int dy, int dx,
int height, int width)
{
- int unit = conp - vc_cons;
+ int unit=0;
+/* int unit = conp - vc_cons;*/
struct display *p = &disp[unit];
+
if (p->fontwidth == 8) {
/* Split blits that cross physical y_wrap case.
* Pathological case involves 4 blits, better to use recursive
@@ -1463,7 +1493,8 @@
static int amicon_clear (struct condata *conp,
int sy, int sx, int height, int width)
{
- int unit = conp - vc_cons;
+ int unit = 0;
+ /*int unit = conp - vc_cons;*/
register struct display *p = &disp[unit];
if (p->fontwidth == 8) {
@@ -1489,7 +1520,7 @@
}
static void amicon_putc_physical_8 (struct display *p,
- int c, int y, int x, int mode)
+ int c, int y, int x, int attr)
{
register u_char *dest;
register u_char *cdat;
@@ -1519,14 +1550,10 @@
*/
for (rows = p->fontheight ; rows-- ; dest += bytes)
- switch (mode) {
- case DM_COPY:
- *dest = *cdat++;
- break;
- case DM_INVERSE:
+ if (attr & 8)
*dest = ~*cdat++;
- break;
- }
+ else
+ *dest = *cdat++;
for (i = 1 ; i < p->scr_depth ; i++) {
dest = p->bitplane[i] + offset;
@@ -1535,14 +1562,14 @@
}
}
-static int amicon_putc (struct condata *conp,
- int c, int y, int x, int mode)
+static int amicon_putc (struct condata *conp, int c, int y, int x)
{
- int unit = conp - vc_cons;
+ int unit = 0;
+ /*int unit = conp - vc_cons;*/
register struct display *p = &disp[unit];
if (p->fontwidth == 8) {
- amicon_putc_physical_8(p, c, real_y_8(p, y) , x, mode);
+ amicon_putc_physical_8(p, c, real_y_8(p, y) , x, conp->vc_attr);
} else {
/* Currently no support for (fontwidth != 8) */
}
@@ -1551,7 +1578,7 @@
}
static void amicon_putcs_physical_8 (struct display *p, const char *s,
- int count, int y, int x, int mode)
+ int count, int y, int x, int attr)
{
register u_char *dest, *cdat;
register ushort rows, bytes;
@@ -1586,8 +1613,7 @@
* d0 -- scratch ; d1 -- count ; d2 -- bytes
*
*/
- switch (mode) {
- case DM_COPY:
+ if (!(attr & 0x8))
__asm__("movel %1,d1 ; beq 5f ; subqw #1,d1\n\t"
"movel %0,a0 ; movel %2,a2\n\t"
"movel %3,a3;movel %4,d2\n\t"
@@ -1611,8 +1637,7 @@
: "g" (dest0), "g" (count), "g" (s),
"g" (p->fontdata), "g" ((ulong) bytes)
: "a0", "a1", "a2", "a3", "d0", "d1", "d2");
- break;
- case DM_INVERSE:
+ else
__asm__("movel %1,d1 ; beq 5f ; subqw #1,d1\n\t"
"movel %0,a0 ; movel %2,a2\n\t"
"movel %3,a3;movel %4,d2\n\t"
@@ -1636,8 +1661,6 @@
: "g" (dest0), "g" (count), "g" (s),
"g" (p->fontdata), "g" ((ulong) bytes)
: "a0", "a1", "a2", "a3", "d0", "d1", "d2", "d3");
- break;
- }
return;
}
#endif
@@ -1663,25 +1686,22 @@
cdat = p->fontdata + (c * p->fontheight);
for (rows = p->fontheight ; rows-- ; dest += bytes)
- switch (mode) {
- case DM_COPY:
+ if (!(attr & 8))
*dest = *cdat++;
- break;
- case DM_INVERSE:
+ else
*dest = ~*cdat++;
- break;
- }
}
}
static int amicon_putcs (struct condata *conp, const char *s,
- int count, int y, int x, int mode)
+ int count, int y, int x)
{
- int unit = conp - vc_cons;
+ int unit = 0;
+ /*int unit = conp - vc_cons;*/
register struct display *p = &disp[unit];
if (p->fontwidth == 8) {
- amicon_putcs_physical_8(p, s, count, real_y_8(p, y) , x, mode);
+ amicon_putcs_physical_8(p, s, count, real_y_8(p, y) , x, conp->vc_attr);
} else {
/* Currently no support for (fontwidth != 8) */
}
@@ -1692,7 +1712,8 @@
static int amicon_cursor (struct condata *conp,
int mode)
{
- int unit = conp - vc_cons;
+ int unit=0;
+ /*int unit = conp - vc_cons;*/
struct display *p = &disp[unit];
if (mode == CM_ERASE) {
@@ -1710,7 +1731,8 @@
static int amicon_scroll (struct condata *conp,
int t, int b, int dir, int count)
{
- int unit = conp - vc_cons;
+ int unit=0;
+ /*int unit = conp - vc_cons;*/
register struct display *p = &disp[unit];
amicon_cursor (conp, CM_ERASE);
@@ -1773,6 +1795,21 @@
static int amicon_switch (struct condata *conp)
{
+ struct display *p = &disp[conp - vc_cons];
+ struct display *old = &disp[fg_console];
+
+ if (!(conp->vc_flags & CON_INITED))
+ return -1;
+
+ p->bitplane[0] = old->bitplane[0]; /* syncing the base address */
+ p->bitplane[1] = old->bitplane[1]; /* syncing the base address */
+ p->bitplane[2] = old->bitplane[2]; /* syncing the base address */
+ p->bitplane[3] = old->bitplane[3]; /* syncing the base address */
+ p->bitplane[4] = old->bitplane[4]; /* syncing the base address */
+ p->bitplane[5] = old->bitplane[5]; /* syncing the base address */
+ p->bitplane[6] = old->bitplane[6]; /* syncing the base address */
+ p->bitplane[7] = old->bitplane[7]; /* syncing the base address */
+
return 0;
}
@@ -1796,4 +1833,3 @@
amicon_init, amicon_deinit, amicon_clear, amicon_putc, amicon_putcs,
amicon_cursor, amicon_scroll, amicon_bmove, amicon_switch, amicon_blank
};
-
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/amiga/config.c linux-0.9pl4/amiga/config.c
--- linux-0.9pl3/amiga/config.c Sun Aug 14 10:29:40 1994
+++ linux-0.9pl4/amiga/config.c Sat Nov 12 09:16:52 1994
@@ -66,25 +66,33 @@
lo = ciab.talo;
hi2 = ciab.tahi;
- if (hi != hi2)
+ if (hi != hi2) {
lo = ciab.talo;
+ hi = hi2;
+ }
ticks = hi << 8 | lo;
if (boot_info.bi_amiga.eclock == NTSC_ECLOCK) {
+#if 0 /* XXX */
+/* reading the ICR clears all interrupts. bad idea! */
if (ticks > NTSC_JIFFY_TICKS - NTSC_JIFFY_TICKS / 100)
/* check for pending interrupt */
if (ciab.icr & CIA_ICR_TA)
offset = 10000;
+#endif
ticks = (NTSC_JIFFY_TICKS-1) - ticks;
- ticks = 10000 * ticks / NTSC_JIFFY_TICKS;
+ ticks = (10000 * ticks) / NTSC_JIFFY_TICKS;
} else {
+#if 0 /* XXX */
+/* reading the ICR clears all interrupts. bad idea! */
if (ticks > PAL_JIFFY_TICKS - PAL_JIFFY_TICKS / 100)
/* check for pending interrupt */
if (ciab.icr & CIA_ICR_TA)
offset = 10000;
+#endif
ticks = (PAL_JIFFY_TICKS-1) - ticks;
- ticks = 10000 * ticks / NTSC_JIFFY_TICKS;
+ ticks = (10000 * ticks) / NTSC_JIFFY_TICKS;
}
return ticks + offset;
@@ -194,21 +202,27 @@
void amiga_reset (void)
{
+ unsigned long jmp_addr040 = VTOP(&&jmp_addr_label040);
unsigned long jmp_addr = VTOP(&&jmp_addr_label);
cli();
if (boot_info.cputype & CPU_68040)
+ /* Setup transparent translation registers for mapping
+ * of 16 MB kernel segment before disabling translation
+ */
__asm__ __volatile__
- ("moveq #0,d0\n\t"
- "bra 2f\n\t"
- ".align 4\n\t" /* align on cache line start */
- "2:\n\t"
- ".long 0x4e7b0003\n\t" /* movec d0,tc */
+ ("movel %0,d0\n\t"
+ "andl #0xff000000,d0\n\t"
+ "orw #0xe020,d0\n\t" /* map 16 MB, enable, cacheable */
+ ".long 0x4e7b0004\n\t" /* movec d0,itt0 */
+ ".long 0x4e7b0006\n\t" /* movec d0,dtt0 */
"jmp %0@\n\t"
: /* no outputs */
- : "a" (jmp_addr)
- : "d0");
+ : "a" (jmp_addr040));
else
+ /* for 680[23]0, just disable translation and jump to the physical
+ * address of the label
+ */
__asm__ __volatile__
("pmove tc,sp@\n\t"
"bclr #7,sp@\n\t"
@@ -216,10 +230,21 @@
"jmp %0@\n\t"
: /* no outputs */
: "a" (jmp_addr));
+ jmp_addr_label040:
+ /* disable translation on '040 now */
+ __asm__ __volatile__
+ ("moveq #0,d0\n\t"
+ ".long 0x4e7b0003\n\t" /* movec d0,tc; disable MMU */
+ : /* no outputs */
+ : /* no inputs */
+ : "d0");
+
jmp_addr_label:
+ /* pickup reset address from AmigaOS ROM, reset devices and jump
+ * to reset address
+ */
__asm__ __volatile__
- ("movew #0x2700,sr\n\t"
- "leal 0x01000000,a0\n\t"
+ ("leal 0x01000000,a0\n\t"
"subl a0@(-0x14),a0\n\t"
"movel a0@(4),a0\n\t"
"subql #2,a0\n\t"
@@ -231,4 +256,5 @@
"jmp a0@");
for (;;);
+
}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/atari/atacon.c linux-0.9pl4/atari/atacon.c
--- linux-0.9pl3/atari/atacon.c Tue Sep 27 22:19:35 1994
+++ linux-0.9pl4/atari/atacon.c Mon Nov 21 18:08:54 1994
@@ -37,14 +37,22 @@
#define CONFIG_ATARI_8PLANE
#undef CONFIG_ATARI_16PLANE
+/* If you do not work with X Windows, hardware scrolling may be
+ * nice...
+ */
+#define HARDWARE_SCROLLING
+
+/* If you want to see underlined characters in color modes, define the
+ * following flag. But note that this effect cannot be restored when
+ * switching VC's!
+ */
+#undef COLOR_UNDERLINING
+
/* To do:
*
* - Do proper Falcon video mode setting, analogous to the TT (but
* much more and better modes possible!)
* - Implement 16 plane mode.
- * - Do a backing store of characters and attributes on the screen
- * for conole switching (or will this be done in the device
- * independent part (console.c) ?)
*
*/
@@ -76,7 +84,16 @@
fontname_8x16[], fontname_8x8[];
+/* Import console_blanked from console.c */
+
+extern int console_blanked;
+/* This macro should return true, if in this mode the
+ * blanking/unblanking is done by blackening and redrawing the screen
+ */
+#define REDRAW_BLANK_MODE(cons) \
+ (boot_info.bi_atari.model == ATARI_TT && \
+ disp[(cons)].shiftmode == TT_HIGH)
/* FONT_CNV does the character conversion necessary if the font
@@ -93,25 +110,16 @@
* Roman
*/
+/* ++andreas: Translation now done in console.c */
+
#ifndef WHOLE_FONT
-#define FONT_CNV(c) ({
- int __rv = 1;
- if ((c >= 32) && (c < 127))
- /* lower half of charset -- normal ASCII */
- c -= 32;
- else if ((c >= 160) && (c < 255))
- /* upper half of charset -- special characters */
- c -= 64;
- else
- /* not defined in charset -- non-printable character */
- __rv = 0;
- __rv;
-})
+#define FONT_CNV(c) (((c) -= 32) >= 0 \
+ && ((c) <= 127 - 32 || ((c) -= 32) >= 160 - 64))
#else
-#define FONT_CNV(c) ((c = conp->vc_translate[c]) != 0)
+#define FONT_CNV(c) (1)
#endif
@@ -140,9 +148,9 @@
void (*clear)( struct condata *conp, register struct display *p,
int sy, int sx, int height, int width);
void (*putc)( struct condata *conp, struct display *p, int c,
- int y, int x, int mode );
+ int y, int x);
void (*putcs)( struct condata *conp, struct display *p,
- const char *s, int count, int y, int x, int mode);
+ const char *s, int count, int y, int x);
void (*rev_char)( struct display *display, int x, int y );
};
@@ -165,9 +173,11 @@
u_char *bitplane; /* pointer to display bitmap; planes
* are interleaved!
*/
+#ifdef HARDWARE_SCROLLING
u_char *screen_base; /* Base of display bitmap for hardware
scrolling */
u_char *screen_end; /* End of first half of display bitmap */
+#endif
u_long *color_map; /* XXX Not yet implemented XXX */
@@ -193,10 +203,13 @@
{ "ttlow", 320 , 480 , 8 } }; /* TT-Low */
static struct tt_vid_type falcon_video_modes[] = {
+ { "sthigh", 640 , 400 , 1 } , /* ST-High */
{ "vga16", 640 , 480 , 4 } , /* VGA 16 colors */
{ "vga4", 640 , 480 , 2 } , /* VGA 4 colors */
{ "vga2", 640 , 480 , 1 } , /* VGA 2 colors */
- { "vga256", 640 , 480 , 8 } /* VGA 256 colors */
+ { "vga256", 640 , 480 , 8 } , /* VGA 256 colors */
+ { "falh2", 896 , 608 , 1 } , /* hires for sblaster */
+ { "falh16", 896 , 608 , 4 } /* hires for sblaster */
};
/* Default color maps for 4 and 2 plane modes. These use the PC-ish
@@ -291,7 +304,7 @@
static void detect_video (int *yres, int *xres, int *depth, int *shiftmode);
static int shifter_init( u_long adr);
-static long atacon_init( struct condata *conp, long mem_start);
+static long atacon_init( struct condata *conp, long mem_start, char **display_desc);
static int atacon_deinit( struct condata *conp);
static __inline__ void *mymemclear_small( void * s, size_t count);
static __inline__ void *mymemclear( void * s, size_t count);
@@ -323,10 +336,9 @@
dx, int height, int width);
static int atacon_clear( struct condata *conp, int sy, int sx, int height,
int width);
-static int atacon_putc( struct condata *conp, int c, int y, int x, int
- mode);
+static int atacon_putc( struct condata *conp, int c, int y, int x);
static int atacon_putcs( struct condata *conp, const char *s, int count,
- int y, int x, int mode);
+ int y, int x);
static int atacon_scroll( struct condata *conp, int t, int b, int dir, int
count);
static int atacon_switch( struct condata *conp);
@@ -337,12 +349,10 @@
display *p, int sy, int sx, int height,
int width );
static void atacon_putc_1_plane( struct condata *conp, struct display *p,
- int c, int y, int x, int mode);
+ int c, int y, int x);
static void atacon_putcs_1_plane( struct condata *conp, struct display *p,
- const char *s, int count, int y, int x,
- int mode);
-static void atacon_rev_char_1_plane( struct display *display, int x, int y
- );
+ const char *s, int count, int y, int x);
+static void atacon_rev_char_1_plane( struct display *display, int x, int y );
#ifdef CONFIG_ATARI_2PLANE
static void atacon_bmove_2_plane( register struct display *p, int sy, int
sx, int dy, int dx, int height, int
@@ -351,12 +361,10 @@
display *p, int sy, int sx, int height,
int width );
static void atacon_putc_2_plane( struct condata *conp, struct display *p,
- int c, int y, int x, int mode);
+ int c, int y, int x);
static void atacon_putcs_2_plane( struct condata *conp, struct display *p,
- const char *s, int count, int y, int x,
- int mode);
-static void atacon_rev_char_2_plane( struct display *display, int x, int y
- );
+ const char *s, int count, int y, int x);
+static void atacon_rev_char_2_plane( struct display *display, int x, int y );
#endif
#ifdef CONFIG_ATARI_4PLANE
static void atacon_bmove_4_plane( register struct display *p, int sy, int
@@ -366,12 +374,10 @@
display *p, int sy, int sx, int height,
int width );
static void atacon_putc_4_plane( struct condata *conp, struct display *p,
- int c, int y, int x, int mode);
+ int c, int y, int x);
static void atacon_putcs_4_plane( struct condata *conp, struct display *p,
- const char *s, int count, int y, int x,
- int mode);
-static void atacon_rev_char_4_plane( struct display *display, int x, int y
- );
+ const char *s, int count, int y, int x);
+static void atacon_rev_char_4_plane( struct display *display, int x, int y );
#endif
#ifdef CONFIG_ATARI_8PLANE
static void atacon_bmove_8_plane( register struct display *p, int sy, int
@@ -381,12 +387,10 @@
display *p, int sy, int sx, int height,
int width );
static void atacon_putc_8_plane( struct condata *conp, struct display *p,
- int c, int y, int x, int mode);
+ int c, int y, int x);
static void atacon_putcs_8_plane( struct condata *conp, struct display *p,
- const char *s, int count, int y, int x,
- int mode);
-static void atacon_rev_char_8_plane( struct display *display, int x, int y
- );
+ const char *s, int count, int y, int x);
+static void atacon_rev_char_8_plane( struct display *display, int x, int y );
#endif
#ifdef CURSOR_DELAY_TIMER
static void atacon_curtimfunc( unsigned long _disp );
@@ -601,8 +605,9 @@
}
}
-static int shifter_init(u_long adr)
+static int shifter_init(u_long vadr)
{
+ u_long adr = VTOP(vadr);
/* Setup Screen Memory */
shifter.bas_hi=(u_char)((adr & 0xff0000) >> 16);
shifter.bas_md=(u_char)((adr & 0x00ff00) >> 8);
@@ -611,12 +616,16 @@
}
-static long atacon_init(struct condata *conp, long mem_start)
+static long atacon_init(struct condata *conp, long mem_start, char **display_desc)
{
int unit = conp - vc_cons;
unsigned long mem_req;
u_char *screen_base;
+ static int master_init = 0;
+ static char mode_name[40];
+ if (!master_init) {
+ master_init = 1;
/* set up the display defaults */
detect_video( &disp[unit].scr_height, &disp[unit].scr_width,
&disp[unit].scr_depth, &disp[unit].shiftmode );
@@ -684,31 +693,76 @@
panic( "atacon_init: %d planes not supported.\n",
disp[unit].scr_depth );
- conp->vc_cols = disp[unit].scr_width / disp[unit].fontwidth;
- conp->vc_rows = disp[unit].scr_height / disp[unit].fontheight;
+#ifdef HARDWARE_SCROLLING
+ /* For hardware scrolling, allocate twice the memory we'd need for
+ * one screen.
+ * The base is rounded up to the next multiple of 8.
+ */
mem_req = (disp[unit].scr_width/8)*disp[unit].scr_height*
disp[unit].scr_depth;
- /* locate the bitplane */
- /* GK: why allocate 2*mem_req ???? */
- screen_base = atari_stram_alloc (mem_req * 2 + 8);
+ screen_base = atari_stram_alloc (mem_req * 2 + 8, &mem_start );
screen_base = (u_char *) (((u_long) screen_base + 7) & ~7);
- disp[unit].screen_base = disp[unit].bitplane = screen_base;
+ disp[unit].screen_base = screen_base;
disp[unit].screen_end = screen_base + mem_req;
+#else
+ /* If hardware scrolling is disabled, but support for X should
+ * come up, allocate the screen mem page-aligned... (begin and end!)
+ */
+ mem_req = (disp[unit].scr_width/8)*disp[unit].scr_height*
+ disp[unit].scr_depth;
+ mem_req = ((mem_req + PAGE_SIZE - 1) & PAGE_MASK) + PAGE_SIZE;
+ screen_base = atari_stram_alloc( mem_req, &mem_start );
+ screen_base = (u_char *) (((u_long)screen_base + PAGE_SIZE - 1) & PAGE_MASK);
+#endif
+ disp[unit].bitplane = screen_base;
memset (screen_base, 0, mem_req);
shifter_init ((unsigned long)screen_base);
+ switch( boot_info.bi_atari.model ) {
+ case ATARI_TT:
+ strcpy( mode_name, "TT native " );
+ strcat( mode_name, tt_video_modes[disp[unit].shiftmode].name );
+ break;
+ case ATARI_FALCON:
+ strcpy( mode_name, "Falcon native " );
+ strcat( mode_name, falcon_video_modes[disp[unit].shiftmode].name );
+ break;
+ default:
+ strcpy( mode_name, "unknown Atari graphics" );
+ break;
+ }
+ *display_desc = mode_name;
#ifdef CURSOR_DELAY_VBL
add_isr( IRQ4, atacon_vbl_handler, 0, NULL );
#endif
+ }
+ else
+ /* Copy all from the first console, maybe allow different
+ display modes later. */
+ disp[unit] = disp[0];
+
+ conp->vc_cols = disp[unit].scr_width / disp[unit].fontwidth;
+ conp->vc_rows = disp[unit].scr_height / disp[unit].fontheight;
+ conp->vc_flags |= CON_INITED;
+ conp->vc_can_do_color = disp[unit].scr_depth != 1;
return mem_start;
}
static int atacon_deinit (struct condata *conp)
{
+ struct display *p = &disp[conp - vc_cons];
+
+ /* You can't deinit a non inited screen nor the console 0. */
+ if (!(conp->vc_flags & CON_INITED) || p == disp)
+ return -1;
+
+ atacon_switch (&vc_cons[0]); /* Always switch to the console 0 */
+ memset (p, 0, sizeof (struct display));
+ conp->vc_flags &= ~CON_INITED;
return 0;
}
@@ -821,6 +875,28 @@
return(0);
}
+static __inline__ void *mymemset(void * s, size_t count)
+
+{
+ if (!count) return(0);
+
+ __asm__ __volatile__
+ ("lsrl #1,%1 ; jcc 1f ; moveb %2,%0@-\n\t"
+ "1: lsrl #1,%1 ; jcc 1f ; movew %2,%0@-\n\t"
+ "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@-\n\t"
+ "1: lsrl #1,%1 ; jcc 1f ; movel %2,%0@- ; movel %2,%0@-\n\t"
+ "1: subql #1,%1 ; jcs 3f\n\t"
+ "2: moveml %2/%3/%4/%5,%0@-\n\t"
+ "dbra %1,2b\n\t"
+ "3:"
+ : "=a" (s), "=d" (count)
+ : "d" (-1), "d" (-1), "d" (-1), "d" (-1),
+ "0" ((char *) s + count), "1" (count)
+ );
+
+ return(0);
+}
+
static __inline__ void *mymemmove(void * d, void * s, size_t count)
{
if (d < s) {
@@ -1384,6 +1460,9 @@
int unit = conp - vc_cons;
struct display *p = &disp[unit];
+ if (REDRAW_BLANK_MODE(unit) && console_blanked)
+ return( 0 );
+
if ((sy <= p->cursor_y && p->cursor_y < sy+height &&
sx <= p->cursor_x && p->cursor_x < sx+width) ||
(dy <= p->cursor_y && p->cursor_y < dy+height &&
@@ -1400,6 +1479,9 @@
int unit = conp - vc_cons;
register struct display *p = &disp[unit];
+ if (REDRAW_BLANK_MODE(unit) && console_blanked)
+ return( 0 );
+
if (sy <= p->cursor_y && p->cursor_y < sy+height &&
sx <= p->cursor_x && p->cursor_x < sx+width)
CURSOR_UNDRAWN();
@@ -1409,31 +1491,36 @@
return(0);
}
-static int atacon_putc (struct condata *conp,
- int c, int y, int x, int mode)
+static int atacon_putc (struct condata *conp, int c, int y, int x)
{
int unit = conp - vc_cons;
register struct display *p = &disp[unit];
+ if (REDRAW_BLANK_MODE(unit) && console_blanked)
+ return( 0 );
+
if (p->cursor_x == x && p->cursor_y == y)
CURSOR_UNDRAWN();
- p->dispsw->putc( conp, p, c, y, x, mode );
+ p->dispsw->putc( conp, p, c, y, x );
return(0);
}
static int atacon_putcs (struct condata *conp, const char *s,
- int count, int y, int x, int mode)
+ int count, int y, int x)
{
int unit = conp - vc_cons;
register struct display *p = &disp[unit];
+ if (REDRAW_BLANK_MODE(unit) && console_blanked)
+ return( 0 );
+
if (p->cursor_y == y &&
x <= p->cursor_x && p->cursor_x < x+count)
CURSOR_UNDRAWN();
- p->dispsw->putcs( conp, p, s, count, y, x, mode );
+ p->dispsw->putcs( conp, p, s, count, y, x );
return(0);
}
@@ -1442,9 +1529,13 @@
static int atacon_scroll (struct condata *conp,
int t, int b, int dir, int count)
{
+ if (REDRAW_BLANK_MODE(conp-vc_cons) && console_blanked)
+ return( 0 );
+
switch (dir) {
case SM_UP:
+#ifdef HARDWARE_SCROLLING
/* Use hardware scrolling if possible */
if (t == 0 && b == conp->vc_rows)
{
@@ -1464,12 +1555,14 @@
shifter_init ((u_long) p->bitplane);
}
else
+#endif
atacon_bmove( conp, t + count, 0, t, 0,
(b-t-count), conp->vc_cols );
atacon_clear( conp, b-count, 0, count, conp->vc_cols );
break;
case SM_DOWN:
+#ifdef HARDWARE_SCROLLING
/* Use hardware scrolling if possible */
if (t == 0 && b == conp->vc_rows)
{
@@ -1490,6 +1583,7 @@
shifter_init ((u_long) p->bitplane);
}
else
+#endif
atacon_bmove( conp, t, 0, t+count, 0,
(b-t-count), conp->vc_cols );
@@ -1519,11 +1613,61 @@
static int atacon_switch (struct condata *conp)
{
+#ifdef HARDWARE_SCROLLING
+ struct display *p = &disp[conp - vc_cons];
+ struct display *old = &disp[fg_console];
+#endif
+
+ if (!(conp->vc_flags & CON_INITED))
+ return -1;
+
+#ifdef HARDWARE_SCROLLING
+ p->bitplane = old->bitplane; /* syncing the base address */
+#endif
return 0;
}
static int atacon_blank (int blank)
{
+ static u_short saved_tt_palette[256];
+ int i;
+
+ if (boot_info.bi_atari.model != ATARI_TT)
+ return 0;
+
+ atacon_cursor( &vc_cons[fg_console], blank ? CM_ERASE : CM_DRAW );
+
+ if (REDRAW_BLANK_MODE(fg_console)) {
+ /* Special treatment for TT High mode: Changing the palette
+ * registers isn't possible, so the screen is filled with black
+ * for blanking and completely restored for unblanking.
+ */
+ if (blank) {
+ struct display *p = &disp[fg_console];
+ mymemset( p->bitplane, p->bytes_per_row * p->scr_height );
+ return( 0 );
+ }
+ else {
+ /* Tell console.c that it has to completely restore the
+ * screen itself
+ */
+ return( 1 );
+ }
+ }
+
+ if (blank)
+ {
+ for (i = 0; i < 256; i++)
+ {
+ saved_tt_palette[i] = tt_palette[i];
+ tt_palette[i] = 0;
+ }
+ }
+ else
+ {
+ for (i = 0; i < 256; i++)
+ tt_palette[i] = saved_tt_palette[i];
+ }
return 0;
}
@@ -1596,8 +1740,29 @@
}
+/* The text effects (bold, reverse, light, underlined, blink) are represented
+ * in the attribute byte as follows: (like a monochrome PC graphics adapter):
+ *
+ * - (attr & 0x80) == 0x00 => not blinking
+ * == 0x80 => blinking (not implemented, ignored)
+ * - (attr & 0x70) != 0 => reverse
+ * == 0 => not reverse
+ * - (attr & 0x03) == 0x01 => underlined
+ * != 0x01 => not underlined
+ * - (attr & 0x08) == 0 => normal intensity
+ * (attr & 0x08) != 0 && (attr & 0x77) == 0 => light (half intensity)
+ * != 0 => bright (bold, double intensity)
+ *
+ * Note that several combinations of effects are not possible with
+ * that representation. Light mode isn't possible if underlined and/or
+ * reverse mode are active. Characters are printed bright in that
+ * cases instead of light :-( Maybe the representation should be
+ * changed (separate bits for each effect)...
+ *
+ */
+
static void atacon_putc_1_plane( struct condata *conp, struct display *p,
- int c, int y, int x, int mode)
+ int c, int y, int x)
{
register u_char *dest;
register u_char *cdat;
@@ -1613,28 +1778,27 @@
dest = p->bitplane + offset;
cdat = p->fontdata + (c * p->fontheight);
- if (conp->vc_intensity != 1 || conp->vc_reverse ^ conp->vc_decscnm) {
+ if ((conp->vc_attr & 0x0b) != 0x01) {
register u_char andmask, xormask, c;
register int bold;
- andmask = (conp->vc_intensity == 0) ? 0x55 : 0xff;
- xormask = (conp->vc_reverse ^ conp->vc_decscnm) ? 0xff : 0;
- bold = (conp->vc_intensity == 2);
+ xormask = (conp->vc_attr & 0x08) ? 0xff : 0; /* reverse */
+ andmask = ((conp->vc_attr & 0x03) == 0) ? 0x55 : 0xff; /* light */
+ bold = ((conp->vc_attr & 0x03) == 2); /* bold/bright */
for (rows = p->fontheight ; rows-- ; dest += bytes) {
c = *cdat++;
- if (rows == 0 && conp->vc_underline) c = 0xff;
+ if (rows == 0 && (conp->vc_attr & 0x04)) c = 0xff;
c = (c & andmask) ^ xormask;
if (bold) c |= c >> 1;
*dest = c;
}
}
else {
-
for (rows = p->fontheight ; rows-- ; dest += bytes)
*dest = *cdat++;
- if (conp->vc_underline)
+ if (conp->vc_attr & 0x04) /* underlined */
dest[-bytes] ^= ~0;
}
}
@@ -1642,15 +1806,14 @@
static void atacon_putcs_1_plane( struct condata *conp, struct
display *p, const char *s,
- int count, int y, int x, int mode)
+ int count, int y, int x)
{
register u_char *dest, *cdat;
register int rows, bytes;
register u_char c;
u_char *dest0;
ulong offset;
- int effects = (conp->vc_underline || conp->vc_intensity != 1 ||
- (conp->vc_reverse ^ conp->vc_decscnm));
+ int effects = (conp->vc_attr & 0x0f) != 0x01;
if (!count) return;
@@ -1721,9 +1884,9 @@
register u_char andmask, xormask, ch;
register int bold;
- andmask = (conp->vc_intensity == 0) ? 0x55 : 0xff;
- xormask = (conp->vc_reverse ^ conp->vc_decscnm) ? 0xff : 0;
- bold = (conp->vc_intensity == 2);
+ xormask = (conp->vc_attr & 0x08) ? 0xff : 0;
+ andmask = ((conp->vc_attr & 0x03) == 0) ? 0x55 : 0xff;
+ bold = ((conp->vc_attr & 0x03) == 2);
while (count--) {
c = *(s++);
@@ -1734,7 +1897,7 @@
for (rows = p->fontheight ; rows-- ; dest += bytes) {
ch = *cdat++;
- if (rows == 0 && conp->vc_underline) ch = 0xff;
+ if (rows == 0 && (conp->vc_attr & 0x04)) ch = 0xff;
ch = (ch & andmask) ^ xormask;
if (bold) ch |= ch >> 1;
*dest = ch;
@@ -1972,7 +2135,7 @@
static void atacon_putc_2_plane( struct condata *conp, struct display *p,
- int c, int y, int x, int mode)
+ int c, int y, int x)
{ register u_char *dest;
register u_char *cdat;
@@ -1996,16 +2159,19 @@
: "a" (dest), "d" ((fdx & eorx) ^ bgx) );
}
+
+#ifdef COLOR_UNDERLINING
if (conp->vc_underline) {
__asm__ __volatile__ ( "movepw %1,%0@(0)" : /* no outputs */
: "a" (dest-bytes), "d" (fgx) );
}
+#endif
}
static void atacon_putcs_2_plane( struct condata *conp, struct
display *p, const char *s,
- int count, int y, int x, int mode)
+ int count, int y, int x)
{ register u_char *dest, *dest0;
register u_char *cdat, c;
@@ -2031,10 +2197,12 @@
: "a" (dest), "d" ((fdx & eorx) ^ bgx) );
}
+#ifdef COLOR_UNDERLINING
if (conp->vc_underline) {
__asm__ __volatile__ ( "movepw %1,%0@(0)" : /* no outputs */
: "a" (dest-bytes), "d" (fgx) );
}
+#endif
INC_2P(dest0);
}
@@ -2255,7 +2423,7 @@
static void atacon_putc_4_plane( struct condata *conp, struct display *p,
- int c, int y, int x, int mode)
+ int c, int y, int x)
{ register u_char *dest;
register u_char *cdat;
register int rows;
@@ -2278,16 +2446,18 @@
: "a" (dest), "d" ((fdx & eorx) ^ bgx) );
}
+#ifdef COLOR_UNDERLINING
if (conp->vc_underline) {
__asm__ __volatile__ ( "movepl %1,%0@(0)" : /* no outputs */
: "a" (dest-bytes), "d" (fgx) );
}
+#endif
}
static void atacon_putcs_4_plane( struct condata *conp, struct
display *p, const char *s,
- int count, int y, int x, int mode)
+ int count, int y, int x)
{ register u_char *dest, *dest0;
register u_char *cdat, c;
register int rows;
@@ -2319,10 +2489,12 @@
: "a" (dest), "d" ((fdx & eorx) ^ bgx) );
}
+#ifdef COLOR_UNDERLINING
if (conp->vc_underline) {
__asm__ __volatile__ ( "movepl %1,%0@(0)" : /* no outputs */
: "a" (dest-bytes), "d" (fgx) );
}
+#endif
INC_4P(dest0);
}
@@ -2554,7 +2726,7 @@
static void atacon_putc_8_plane( struct condata *conp, struct display *p,
- int c, int y, int x, int mode)
+ int c, int y, int x)
{ register u_char *dest;
register u_char *cdat;
register int rows;
@@ -2582,6 +2754,7 @@
);
}
+#ifdef COLOR_UNDERLINING
if (conp->vc_underline) {
__asm__ __volatile__
( "movepl %1,%0@(0)\n\t"
@@ -2590,12 +2763,13 @@
: "a" (dest-bytes), "d" (fgx1), "d" (fgx2)
);
}
+#endif
}
static void atacon_putcs_8_plane( struct condata *conp, struct
display *p, const char *s,
- int count, int y, int x, int mode)
+ int count, int y, int x)
{ register u_char *dest, *dest0;
register u_char *cdat, c;
@@ -2634,6 +2808,7 @@
);
}
+#ifdef COLOR_UNDERLINING
if (conp->vc_underline) {
__asm__ __volatile__
( "movepl %1,%0@(0)\n\t"
@@ -2642,6 +2817,7 @@
: "a" (dest-bytes), "d" (fgx1), "d" (fgx2)
);
}
+#endif
INC_8P(dest0);
}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/atari/ataints.c linux-0.9pl4/atari/ataints.c
--- linux-0.9pl3/atari/ataints.c Thu Sep 29 20:15:49 1994
+++ linux-0.9pl4/atari/ataints.c Mon Nov 21 18:08:55 1994
@@ -51,24 +51,29 @@
/* GK:
* HBL IRQ handler for Falcon. Nobody needs it :-)
+ * ++andreas: raise ipl to disable further interrupts.
*/
asmlinkage void falcon_hblhandler(void);
asm(".text
- _falcon_hblhandler: rte");
+_falcon_hblhandler:
+ moveml d0/a0,sp@-
+ btst #4,sp@(14) /* throwaway frame? */
+ beq 1f
+ movec msp,a0 /* yes, use master stack */
+ bra 2f
+1: lea sp@(8),a0 /* else, use interrupt stack */
+2: movew a0@,d0
+ andw #0xf8ff,d0
+ orw #0x0200,d0 /* set saved ipl to 2 */
+ movew d0,a0@
+ moveml sp@+,d0/a0
+ rte");
extern void atari_microwire_cmd( int cmd );
void atari_init_INTS (void)
{
- int i;
-
- /* GK: BSS is not cleared by bootstrap, so we must explicitly
- * initialize the interrupt sources list
- */
- for( i = 0; i < NUM_ATARI_SOURCES; ++i )
- ata_lists[i] = 0;
-
/* Initialize the MFP(s) */
mfp.vec_adr = 0x48; /* Software EOI-Mode */
@@ -153,11 +158,37 @@
return 1;
}
+#if 0
+
+#include <linux/mm.h>
+extern unsigned long RCont;
+
+#define TEST_PAGE(str,adr) \
+ do { \
+ unsigned long flags; \
+ save_flags(flags);; cli(); \
+ if (*(unsigned long *)0xc03ff000 != RCont) { \
+ printk("*0xc03ff000 = %08lx mem_map[]=%d\n", \
+ (RCont = *(unsigned long *)0xc03ff000), \
+ mem_map[MAP_NR(0xc03ff000)] ); \
+ printk("%s ",(str)); \
+ printk("%08lx\n",(unsigned long)(adr)); \
+ } \
+ restore_flags(flags); \
+ } while(0)
+
+#else
+
+#define TEST_PAGE(str,adr) do {} while(0)
+
+#endif
+
void atari_process_int (int level, struct intframe *fp)
{
ushort sr;
int mask;
+TEST_PAGE("start irq level",level);
/* Lower the ipl to let interrupts with higher priority come through */
asm volatile ("movew sr,%0" : "=dm" (sr));
sr -= 0x100;
@@ -168,6 +199,11 @@
call_isr_list (ata_lists[level], fp);
+ /* Raise ipl again to avoid stacked interrupts. */
+ asm volatile ("movew sr,%0" : "=dm" (sr));
+ sr += 0x100;
+ asm volatile ("movew %0,sr" : : "dm" (sr));
+
/* acknowledge the interrupt */
mask = ~(1 << (level & 7));
switch (level >> 3)
@@ -186,7 +222,7 @@
break;
case 4:
case 5:
- /* TODO: SCC interrupt acknowledge */
+ scc.cha_a_ctrl = 070; /* Reset highest IUS */
break;
}
}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/atari/atakeyb.c linux-0.9pl4/atari/atakeyb.c
--- linux-0.9pl3/atari/atakeyb.c Sun Aug 14 10:30:00 1994
+++ linux-0.9pl4/atari/atakeyb.c Mon Nov 7 22:07:47 1994
@@ -35,18 +35,26 @@
/*
* ++roman: The following changes were applied manually:
*
- * - The Alt (= Meta) key works in combination with Shift and Control, e.g. Alt+Shift+a sends Meta-A (0xc1),
- * Alt+Control+A sends Meta-Ctrl-A (0x81) ...
+ * - The Alt (= Meta) key works in combination with Shift and
+ * Control, e.g. Alt+Shift+a sends Meta-A (0xc1), Alt+Control+A sends
+ * Meta-Ctrl-A (0x81) ...
*
- * - The parentheses on the keypad send '(' and ')' with all modifiers (as would do e.g. keypad '+'), but they cannot
- * be used as application keys (i.e. sending Esc O c).
+ * - The parentheses on the keypad send '(' and ')' with all
+ * modifiers (as would do e.g. keypad '+'), but they cannot be used as
+ * application keys (i.e. sending Esc O c).
*
- * - HELP and UNDO are mapped to be F11 and F12, resp. This way, applications that allow their own keyboard mappings
- * (e.g. tcsh, X Windows) can be configured to use them in the way the Label suggests (providing help or undoing).
+ * - HELP and UNDO are mapped to be F21 and F24, resp, that send the
+ * codes "\E[M" and "\E[P". (This is better than the old mapping to
+ * F11 and F12, because these codes are on Shift+F1/2 anyway.) This
+ * way, applications that allow their own keyboard mappings
+ * (e.g. tcsh, X Windows) can be configured to use them in the way
+ * the label suggests (providing help or undoing).
*
- * - Console switching is done with Alt+Fx (consoles 1..10) and Shift+Alt+Fx (consoles 11..20).
+ * - Console switching is done with Alt+Fx (consoles 1..10) and
+ * Shift+Alt+Fx (consoles 11..20).
*
- * - The misc. special function implemented in the kernel are mapped to the following key combinations:
+ * - The misc. special function implemented in the kernel are mapped
+ * to the following key combinations:
*
* ClrHome -> Home/Find
* Shift + ClrHome -> End/Select
@@ -61,9 +69,13 @@
* Alt + Insert -> stop/start output (same as ^S/^Q)
* Alt + Up -> Scroll back console (if implemented)
* Alt + Down -> Scroll forward console (if implemented)
+ * Alt + CapsLock -> NumLock
*
*/
+#define K_F21 K_MACRO
+#define K_F24 K_PAUSE
+
unsigned short atakey_map[NR_KEYMAPS][NR_KEYS] = {
{ /* no modifiers */
/* 00-03 */ K_HOLE, '['&0x1f, '1', '2',
@@ -90,7 +102,7 @@
/* 54-57 */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 58-5b */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 5c-5f */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
-/* 60-63 */ '<', K_F12, K_HELP, '(',
+/* 60-63 */ K_HOLE, K_F24, K_F21, '(',
/* 64-67 */ ')', K_PSLASH, K_PSTAR, K_P7,
/* 68-6b */ K_P8, K_P9, K_P4, K_P5,
/* 6c-6f */ K_P6, K_P1, K_P2, K_P3,
@@ -123,7 +135,7 @@
/* 54-57 */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 58-5b */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 5c-5f */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
-/* 60-63 */ '>', K_BREAK, K_SH_MEM, '(',
+/* 60-63 */ K_HOLE, K_BREAK, K_SH_MEM, '(',
/* 64-67 */ ')', K_PSLASH, K_PSTAR, K_P7,
/* 68-6b */ K_P8, K_P9, K_P4, K_P5,
/* 6c-6f */ K_P6, K_P1, K_P2, K_P3,
@@ -222,7 +234,7 @@
/* 54-57 */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 58-5b */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 5c-5f */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
-/* 60-63 */ '\\'&0x1f, K_HOLE, K_SH_REGS, '(',
+/* 60-63 */ K_HOLE, K_F24, K_SH_REGS, '(',
/* 64-67 */ ')', K_PSLASH, K_PSTAR, K_P7,
/* 68-6b */ K_P8, K_P9, K_P4, K_P5,
/* 6c-6f */ K_P6, K_P1, K_P2, K_P3,
@@ -255,7 +267,7 @@
/* 54-57 */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 58-5b */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 5c-5f */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
-/* 60-63 */ K_HOLE, K_HOLE, K_HELP, '(',
+/* 60-63 */ K_HOLE, K_HOLE, K_HOLE, '(',
/* 64-67 */ ')', K_PSLASH, K_PSTAR, K_P7,
/* 68-6b */ K_P8, K_P9, K_P4, K_P5,
/* 6c-6f */ K_P6, K_P1, K_P2, K_P3,
@@ -344,7 +356,7 @@
/* 2c-2f */ K(KT_META,'z'), K(KT_META,'x'), K(KT_META,'c'), K(KT_META,'v'),
/* 30-33 */ K(KT_META,'b'), K(KT_META,'n'), K(KT_META,'m'), K(KT_META,','),
/* 34-37 */ K(KT_META,'.'), K(KT_META,'/'), K_SHIFT, K_HOLE,
-/* 38-3b */ K_ALT, K(KT_META,' '), K_CAPS, K(KT_CONS,0),
+/* 38-3b */ K_ALT, K(KT_META,' '), K_NUM, K(KT_CONS,0),
/* 3c-3f */ K(KT_CONS,1), K(KT_CONS,2), K(KT_CONS,3), K(KT_CONS,4),
/* 40-43 */ K(KT_CONS,5), K(KT_CONS,6), K(KT_CONS,7), K(KT_CONS,8),
/* 44-47 */ K(KT_CONS,9), K_HOLE, K_HOLE, K_FIND,
@@ -354,7 +366,7 @@
/* 54-57 */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 58-5b */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 5c-5f */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
-/* 60-63 */ K(KT_META,'<'), K_CONS, K_SH_STAT, '(',
+/* 60-63 */ K_HOLE, K_CONS, K_SH_STAT, '(',
/* 64-67 */ ')', K_PSLASH, K_PSTAR, K_ASC7,
/* 68-6b */ K_ASC8, K_ASC9, K_ASC4, K_ASC5,
/* 6c-6f */ K_ASC6, K_ASC1, K_ASC2, K_ASC3,
@@ -387,7 +399,7 @@
/* 54-57 */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 58-5b */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 5c-5f */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
-/* 60-63 */ K(KT_META,'>'), K_HOLE, K_HELP, '(',
+/* 60-63 */ K_HOLE, K_HOLE, K_HOLE, '(',
/* 64-67 */ ')', K_PSLASH, K_PSTAR, K_P7,
/* 68-6b */ K_P8, K_P9, K_P4, K_P5,
/* 6c-6f */ K_P6, K_P1, K_P2, K_P3,
@@ -486,7 +498,7 @@
/* 54-57 */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 58-5b */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 5c-5f */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
-/* 60-63 */ K(KT_META,'\\'&0x1f), K_HOLE, K_HELP, '(',
+/* 60-63 */ K_HOLE, K_HOLE, K_HOLE, '(',
/* 64-67 */ ')', K_PSLASH, K_PSTAR, K_P7,
/* 68-6b */ K_P8, K_P9, K_P4, K_P5,
/* 6c-6f */ K_P6, K_P1, K_P2, K_P3,
@@ -519,7 +531,7 @@
/* 54-57 */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 58-5b */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 5c-5f */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
-/* 60-63 */ K_HOLE, K_HOLE, K_HELP, '(',
+/* 60-63 */ K_HOLE, K_HOLE, K_HOLE, '(',
/* 64-67 */ ')', K_PSLASH, K_PSTAR, K_P7,
/* 68-6b */ K_P8, K_P9, K_P4, K_P5,
/* 6c-6f */ K_P6, K_P1, K_P2, K_P3,
@@ -552,7 +564,7 @@
/* 54-57 */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 58-5b */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 5c-5f */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
-/* 60-63 */ K_HOLE, K_HOLE, K_HELP, K_HOLE,
+/* 60-63 */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 64-67 */ K_HOLE, K_PSLASH, K_PSTAR, K_P7,
/* 68-6b */ K_P8, K_P9, K_P4, K_P5,
/* 6c-6f */ K_P6, K_P1, K_P2, K_P3,
@@ -585,7 +597,7 @@
/* 54-57 */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 58-5b */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 5c-5f */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
-/* 60-63 */ K_HOLE, K_HOLE, K_HELP, K_HOLE,
+/* 60-63 */ K_HOLE, K_HOLE, K_HOLE, K_HOLE,
/* 64-67 */ K_HOLE, K_PSLASH, K_PSTAR, K_P7,
/* 68-6b */ K_P8, K_P9, K_P4, K_P5,
/* 6c-6f */ K_P6, K_P1, K_P2, K_P3,
@@ -615,69 +627,31 @@
#define DEFAULT_KEYB_REP_DELAY (HZ/4)
#define DEFAULT_KEYB_REP_RATE (HZ/25)
+/* These could be settable by some ioctl() in future... */
unsigned int key_repeat_delay = DEFAULT_KEYB_REP_DELAY;
unsigned int key_repeat_rate = DEFAULT_KEYB_REP_RATE;
-
-#if 0
-
-/*
- * This table maps the Atari keyboard scan codes to
- * the Linux "virtual" scan codes. These "virtual" scan
- * codes mostly conform to the scan codes given by an IBM
- * keyboard, except that the E0 xx codes are given unique
- * codes. These are the codes > 96. See linux/keyboard.h
- */
-
-static unsigned char atari_kmap[] =
-{
-/* 00-03 */ KB_NONE, KB_ESCAPE, KB_1, KB_2,
-/* 04-07 */ KB_3, KB_4, KB_5, KB_6,
-/* 08-0B */ KB_7, KB_8, KB_9, KB_0,
-/* 0C-0F */ KB_DASH, KB_EQUAL, KB_BACKSPACE, KB_TAB,
-/* 10-13 */ KB_Q, KB_W, KB_E, KB_R,
-/* 14-17 */ KB_T, KB_Y, KB_U, KB_I,
-/* 18-1B */ KB_O, KB_P, KB_LSQUARE, KB_RSQUARE,
-/* 1C-1F */ KB_ENTER, KB_LCTRL, KB_A, KB_S,
-/* 20-23 */ KB_D, KB_F, KB_G, KB_H,
-/* 24-27 */ KB_J, KB_K, KB_L, KB_SEMICOLON,
-/* 28-2B */ KB_APOSTROPHE, KB_BACKQUOTE, KB_LSHIFT, KB_BACKSLASH,
-/* 2C-2F */ KB_Z, KB_X, KB_C, KB_V,
-/* 30-33 */ KB_B, KB_N, KB_M, KB_COMMA,
-/* 34-37 */ KB_PERIOD, KB_SLASH, KB_RSHIFT, KB_NONE,
-/* 38-3B */ KB_LALT, KB_SPACE, KB_CAPS, KB_F1,
-/* 3C-3F */ KB_F2, KB_F3, KB_F4, KB_F5,
-/* 40-43 */ KB_F6, KB_F7, KB_F8, KB_F9,
-/* 44-47 */ KB_F10, KB_NONE, KB_NONE, KB_FIND,
-/* 48-4B */ KB_UP, KB_NONE, KB_KPMINUS, KB_LEFT,
-/* 4C-4F */ KB_NONE, KB_RIGHT, KB_KPPLUS, KB_NONE,
-/* 50-53 */ KB_DOWN, KB_NONE, KB_INSERT, KB_DELETE,
-/* 54-57 */ KB_NONE, KB_NONE, KB_NONE, KB_NONE,
-/* 58-5B */ KB_NONE, KB_NONE, KB_NONE, KB_NONE,
-/* 5B-5F */ KB_NONE, KB_NONE, KB_NONE, KB_NONE,
-/* 60-63 */ KB_LESS, KB_UNDO, KB_HELP, KB_KPLPAR,
-/* 64-67 */ KB_KPRPAR, KB_KPDIVIDE, KB_KPMULTIPLY,KB_KP7,
-/* 68-6B */ KB_KP8, KB_KP9, KB_KP4, KB_KP5,
-/* 6C-6F */ KB_KP6, KB_KP1, KB_KP2, KB_KP3,
-/* 70-73 */ KB_KP0, KB_KPDECIMAL, KB_KPENTER, KB_NONE,
-/* 74-77 */ KB_NONE, KB_NONE, KB_NONE, KB_NONE,
-/* 78-7B */ KB_NONE, KB_NONE, KB_NONE, KB_NONE,
-/* 7C-7F */ KB_NONE, KB_NONE, KB_NONE, KB_NONE
-};
-
-#endif
-
-
static unsigned char rep_scancode;
static struct timer_list atakeyb_rep_timer = { NULL, NULL, 0, 0, atakeyb_rep };
static void atakeyb_rep( unsigned long ignore )
-{
+{ unsigned long flags;
+
+ /* process_scancode() mucks around with the tty queues without
+ * disabling interrupts! It assumes that it is called from an irq...
+ */
+ save_flags(flags);
+ cli();
+
+ del_timer( &atakeyb_rep_timer );
atakeyb_rep_timer.expires = key_repeat_rate;
add_timer( &atakeyb_rep_timer );
+
process_scancode( rep_scancode );
+
+ restore_flags(flags);
}
@@ -687,13 +661,22 @@
int scancode;
int break_flag;
+ repeat:
acia_stat = acia.key_ctrl;
/* check out if the interrupt came from this ACIA */
if (!(acia_stat & ACIA_IRQ))
return;
+ if (acia_stat & ACIA_OVRN)
+ {
+ /* a very fast typist or a slow system, give a warning */
+ printk( "Keyboard overrun\n" );
+ goto get_key;
+ }
+
if (acia_stat & ACIA_RDRF) /* received a character */
{
+ get_key:
scancode = acia.key_data; /* get it or reset the ACIA, I'll get it! */
switch (kb_state.state)
{
@@ -809,13 +792,13 @@
if (acia_stat & (ACIA_FE | ACIA_PE))
{
- panic("Error in keyboard communication");
+ printk("Error in keyboard communication");
}
- if (acia_stat & ACIA_OVRN)
- {
- /* a very fast typist or a slow system, give a warning */
- }
+ /* process_scancode() can take a lot of time, so check again if
+ * some character arrived
+ */
+ goto repeat;
}
#ifdef KEYB_WRITE_INTERRUPT
@@ -1098,6 +1081,7 @@
kb_state.len = 0;
/* enable ACIA Interrupts */
+ mfp.active_edge &= ~0x10;
mfp.int_en_b |= 0x40;
return kmem_start;
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/atari/config.c linux-0.9pl4/atari/config.c
--- linux-0.9pl3/atari/config.c Sun Aug 14 10:30:00 1994
+++ linux-0.9pl4/atari/config.c Mon Nov 21 18:08:55 1994
@@ -33,6 +33,7 @@
#include <linux/atariints.h>
#include <asm/system.h>
+#include <asm/io.h>
/* ++andreas: timer interrupt fixed to have perfect 100 Hz */
@@ -93,14 +94,14 @@
#define RTC_READ(reg) \
({ unsigned char __val; \
- tt_rtc.regsel = (reg); \
+ outb(reg,&tt_rtc.regsel); \
__val = tt_rtc.data; \
__val; \
})
#define RTC_WRITE(reg,val) \
do { \
- tt_rtc.regsel = (reg); \
+ outb(reg,&tt_rtc.regsel); \
tt_rtc.data = (val); \
} while(0)
@@ -108,15 +109,11 @@
void atari_gettod( struct mktime *time )
{
- int i;
unsigned char ctrl;
+ unsigned short tos_version;
- for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
- if (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)
- break;
- for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms*/
- if (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP))
- break;
+ while (!(RTC_READ(RTC_FREQ_SELECT) & RTC_UIP)) ;
+ while (RTC_READ(RTC_FREQ_SELECT) & RTC_UIP) ;
time->sec = RTC_READ(RTC_SECONDS);
time->min = RTC_READ(RTC_MINUTES);
@@ -125,10 +122,6 @@
time->mon = RTC_READ(RTC_MONTH);
time->year = RTC_READ(RTC_YEAR);
- /* Adjust values (let the setup valid for TOS) */
- time->mon--;
- time->year += 68;
-
ctrl = RTC_READ(RTC_CONTROL);
if (!(ctrl & RTC_DM_BINARY)) {
@@ -145,6 +138,11 @@
time->hour += 12;
}
}
+ /* Adjust values (let the setup valid) */
+ time->mon--;
+ /* Tos version at Physical 2 */
+ tos_version = *(unsigned short *)PTOV( 2 );
+ time->year += (tos_version < 0x306) ? 70 : 68;
}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/atari/joystick.c linux-0.9pl4/atari/joystick.c
--- linux-0.9pl3/atari/joystick.c Sun Aug 14 10:30:33 1994
+++ linux-0.9pl4/atari/joystick.c Mon Nov 21 18:08:55 1994
@@ -1,15 +1,21 @@
/*
* Atari Joystick Driver for Linux
* by Robert de Vries (robert@and.nl) 19Jul93
+ *
+ * 16 Nov 1994 Andreas Schwab
+ * Support for three button mouse (shamelessly stolen from MiNT)
+ * third button wired to one of the joystick directions on joystick 1
*/
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/atarikb.h>
#include <linux/atari_joystick.h>
+#include <linux/atari_mouse.h>
#include <asm/segment.h>
static struct joystick_status joystick[2];
+extern int atari_mouse_buttons; /* for three-button mouse */
void joystick_interrupt(char *buf)
{
@@ -21,6 +27,18 @@
joystick[j].fire = (buf[1] & 0x80) >> 7;
joystick[j].ready = 1;
wake_up_interruptible(&joystick[j].wait);
+
+ /* For three-button mouse emulation fake a mouse packet */
+ if (j == 1 && (buf[1] & 1) != ((atari_mouse_buttons & 2) >> 1))
+ {
+ char faked_packet[3];
+
+ atari_mouse_buttons = (atari_mouse_buttons & 5) | ((buf[1] & 1) << 1);
+ faked_packet[0] = atari_mouse_buttons;
+ faked_packet[1] = 0;
+ faked_packet[2] = 0;
+ atari_mouse_interrupt (faked_packet);
+ }
/* ikbd_joystick_event_on(); */
}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/atari/stdma.c linux-0.9pl4/atari/stdma.c
--- linux-0.9pl3/atari/stdma.c Tue Sep 27 22:21:22 1994
+++ linux-0.9pl4/atari/stdma.c Tue Nov 8 18:31:59 1994
@@ -14,20 +14,31 @@
/* This file contains some function for controlling the access to the */
/* ST-DMA chip that may be shared between devices. Currently we have: */
/* TT: Floppy and ACSI bus */
-/* Falcon: Floppy, SCSI and IDE */
+/* Falcon: Floppy and SCSI */
/* */
/* The controlling functions set up a wait queue for access to the */
/* ST-DMA chip. Callers to stdma_lock() that cannot granted access are */
/* put onto a queue and waked up later if the owner calls */
/* stdma_release(). Additionally, the caller gives his interrupt */
/* service routine to stdma_lock(). */
+/* */
+/* On the Falcon, the IDE bus uses just the ACSI/Floppy interrupt, but */
+/* not the ST-DMA chip itself. So falhd.c needs not to lock the */
+/* chip. The interrupt is routed to falhd.c if IDE is configured, the */
+/* model is a Falcon and the interrupt was caused by the HD controller */
+/* (can be determined by looking at its status register). */
+
+#include <linux/config.h>
#include <linux/types.h>
+#include <linux/genhd.h>
#include <linux/sched.h>
+#include <linux/bootinfo.h>
#include <linux/atari_stdma.h>
#include <linux/atariints.h>
#include <linux/atarihw.h>
-
+#include <linux/atarihdreg.h>
+#include <asm/io.h>
static int stdma_locked = 0; /* the semaphore */
static isrfunc stdma_isr = NULL; /* int func to be called */
@@ -40,6 +51,9 @@
/***************************** Prototypes *****************************/
static void stdma_int( struct intframe *fp, void *data );
+#ifdef CONFIG_ATARI_FALCON_IDE
+extern void hd_interrupt( struct intframe *fp, void *data );
+#endif
/************************* End of Prototypes **************************/
@@ -125,6 +139,27 @@
/*
+ * Function: int stdma_islocked( void )
+ *
+ * Purpose: Check if the ST-DMA is currently locked.
+ * Note: This function should be called only with interrupts disbabled
+ * to avoid race conditions. Also, the returned status is only
+ * valid as long as the ints remain disabled.
+ *
+ * Inputs: none
+ *
+ * Returns: != 0 if locked, 0 otherwise
+ *
+ */
+
+int stdma_islocked( void )
+
+{
+ return( stdma_locked );
+}
+
+
+/*
* Function: void stdma_init( void )
*
* Purpose: Initialize the ST-DMA chip access controlling.
@@ -157,6 +192,12 @@
static void stdma_int( struct intframe *fp, void *data )
{
+#ifdef CONFIG_ATARI_FALCON_IDE
+ if (boot_info.bi_atari.model == ATARI_FALCON &&
+ (inb (HD_IRQ_TEST) & 0xad))
+ hd_interrupt( fp, data );
+ else
+#endif
if (stdma_isr)
(*stdma_isr)( fp, stdma_isr_data );
}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/atari/stram.c linux-0.9pl4/atari/stram.c
--- linux-0.9pl3/atari/stram.c Sun Aug 14 10:30:34 1994
+++ linux-0.9pl4/atari/stram.c Mon Nov 7 22:10:07 1994
@@ -1,8 +1,11 @@
+
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/bootinfo.h>
#include <linux/atarihw.h>
+#if 0
+
struct stram_desc
{
unsigned first:1;
@@ -139,3 +142,99 @@
edp = dp2;
}
}
+
+#else
+
+#include <linux/mm.h>
+
+/* ++roman:
+ *
+ * New version of ST-Ram buffer allocation. Instead of using the
+ * 1 MB - 4 KB that remain when the the ST-Ram chunk starts at $1000
+ * (1 MB granularity!), such buffers are reserved like this:
+ *
+ * - If the kernel resides in ST-Ram anyway, we can take the buffer
+ * from behind the current kernel data space the normal way
+ * (incrementing start_mem).
+ *
+ * - If the kernel is in TT-Ram, stram_init() initializes start and
+ * end of the available region. Buffers are allocated from there
+ * and mem_init() later marks the such used pages as reserved.
+ * Since each TT-Ram chunk is at least 4 MB in size, I hope there
+ * won't be an overrun of the ST-Ram region by normal kernel data
+ * space.
+ *
+ * For that, ST-Ram may only be allocated while kernel initialization
+ * is going on, or exactly: before mem_init() is called. There is also
+ * no provision now for freeing ST-Ram buffers. It seems that isn't
+ * really needed.
+ *
+ * ToDo:
+ * Check the high level scsi code what is done when the
+ * UNCHECKED_ISA_DMA flag is set. It guess, it is just a test for adr
+ * < 16 Mega. There should be call to atari_stram_alloc() instead.
+ *
+ * Also ToDo:
+ * Go through head.S and delete parts no longer needed (transparent
+ * mapping of ST-Ram etc.)
+ *
+ */
+
+
+unsigned long rsvd_stram_beg, rsvd_stram_end;
+ /* Start and end of the reserved ST-Ram region */
+static unsigned long stram_end;
+ /* Overall end of ST-Ram */
+
+
+void atari_stram_init( void )
+
+{ int i;
+
+ for( i = 0; i < boot_info.num_memory; ++i ) {
+ if (boot_info.memory[i].addr == 0) {
+ rsvd_stram_beg = PTOV( 0x800 ); /* skip super-only first 2 KB! */
+ rsvd_stram_end = rsvd_stram_beg;
+ stram_end = rsvd_stram_beg - 0x800 + boot_info.memory[i].size;
+ return;
+ }
+ }
+ /* Should never come here! (There is always ST-Ram!) */
+}
+
+
+void *atari_stram_alloc( long size, unsigned long *start_mem )
+
+{
+ static int kernel_in_stram = -1;
+
+ void *adr = 0;
+
+ if (kernel_in_stram < 0)
+ kernel_in_stram = (PTOV( 0 ) == KSTART_ADDR);
+
+ if (kernel_in_stram) {
+ /* Get memory from kernel data space */
+ adr = (void *) *start_mem;
+ *start_mem += size;
+ }
+ else {
+ /* Get memory from rsvd_stram_beg */
+ if (rsvd_stram_end + size < stram_end) {
+ adr = (void *) rsvd_stram_end;
+ rsvd_stram_end += size;
+ }
+ }
+
+ return( adr );
+}
+
+void atari_stram_free( void *ptr )
+
+{
+ /* Sorry, this is a dummy. It isn't needed anyway. */
+}
+
+#endif
+
+
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/config.in linux-0.9pl4/config.in
--- linux-0.9pl3/config.in Thu Sep 29 18:27:15 1994
+++ linux-0.9pl4/config.in Fri Nov 11 21:01:08 1994
@@ -19,6 +19,7 @@
if [ "$CONFIG_ATARI" = "y" ]
bool 'Atari Falcon IDE harddisk support' CONFIG_ATARI_FALCON_IDE y
bool 'Limit Floppy drive to DD only' CONFIG_FLOPPY_DD_ONLY n
+bool 'Atari ACSI support' CONFIG_ATARI_ACSI y
fi
bool 'TCP/IP networking' CONFIG_INET y
bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
@@ -106,7 +107,7 @@
bool 'xiafs filesystem support' CONFIG_XIA_FS n
bool 'msdos fs support' CONFIG_MSDOS_FS y
bool '/proc filesystem support' CONFIG_PROC_FS y
-bool 'NFS filesystem support' CONFIG_NFS_FS n
+bool 'NFS filesystem support' CONFIG_NFS_FS y
bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y
bool 'System V and Coherent filesystem support' CONFIG_SYSV_FS n
bool 'Amiga FFS filesystem support' CONFIG_AFFS_FS y
@@ -120,7 +121,7 @@
if [ "$CONFIG_ATARI" = "y" ]
bool 'Atari mouse support' CONFIG_ATARIMOUSE y
fi
-bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION n
+bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION y
bool 'QIC-02 tape support' CONFIG_TAPE_QIC02 n
bool 'QIC-117 tape support' CONFIG_FTAPE n
if [ "$CONFIG_FTAPE" = "y" ]
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/block/Makefile linux-0.9pl4/drivers/block/Makefile
--- linux-0.9pl3/drivers/block/Makefile Sun Aug 14 10:30:43 1994
+++ linux-0.9pl4/drivers/block/Makefile Mon Nov 7 22:11:26 1994
@@ -57,6 +57,11 @@
SRCS := $(SRCS) xd.c
endif
+ifdef CONFIG_ATARI_ACSI
+OBJS := $(OBJS) acsi.o
+SRCS := $(SRCS) acsi.c
+endif
+
all: block.a
block.a: $(OBJS)
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/block/acsi.c linux-0.9pl4/drivers/block/acsi.c
--- linux-0.9pl3/drivers/block/acsi.c Wed Dec 31 19:00:00 1969
+++ linux-0.9pl4/drivers/block/acsi.c Thu Nov 24 21:37:38 1994
@@ -0,0 +1,1442 @@
+/*
+ * acsi.c -- Device driver for Atari ACSI hard disks
+ *
+ * Copyright 1994 Roman Hodek
+ * EMail: rnhodek@cip.informatik.uni-erlangen.de (Internet)
+ * or: Roman_Hodek@n.maus.de (MausNet, NO mail > 16 KB!)
+ *
+ * Some parts are based on hd.c by Linus Thorvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ */
+
+/*
+ * Still to in this file:
+ * - There is also the "bits get set somewhere while DMA" problem as
+ * with the floppy driver. See there. Maybe this is a hardware problem.
+ * - If a command ends with an error status (!= 0), the following
+ * REQUEST SENSE commands (4 to fill the ST-DMA FIFO) are done by
+ * polling the _IRQ signal (not interrupt-driven). This should be
+ * avoided in future because it takes up a non-neglectible time in
+ * the interrupt service routine while interrupts are disabled.
+ * Maybe a timer interrupt will get lost :-(
+ */
+
+/*
+ * General notes:
+ *
+ * - All ACSI devices (disks, CD-ROMs, ...) use major number 28.
+ * Minors are organized like it is with SCSI: The upper 4 bits
+ * identify the device, the lower 4 bits the partition.
+ * The device numbers (the upper 4 bits) are given in the same
+ * order as the devices are found on the bus.
+ * - Up to 8 LUNs are supported for each target, but only a total of
+ * 16 devices (due to minor numbers...). Note that Atari allows
+ * only a maximum of 4 targets (i.e. controllers, not devices) on
+ * the ACSI bus!
+ * - The SLM laser printer is not supported. In many ways, it behaves
+ * different than other ACSI devices and there are other problems,
+ * too (DMA size is not a multiple of 512, intervention necessary
+ * while DMA-ing the page data).
+ * - A optimizing scheme similar to SCSI scatter-gather is implemented.
+ * - Removable media are supported. After a medium change to device
+ * is reinitialized (partition check etc.). Also, if the device
+ * knows the PREVENT/ALLOW MEDIUM REMOVAL command, the door should
+ * be locked and unlocked when mounting the first or unmounting the
+ * last filesystem on the device. The code is untested, because I
+ * don't have a removable harddisk.
+ *
+ */
+
+
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/genhd.h>
+#include <linux/delay.h>
+
+#include <linux/bootinfo.h>
+#include <linux/interrupt.h>
+#include <linux/atarihw.h>
+#include <linux/atari_stdma.h>
+#include <linux/atari_rootsec.h>
+
+#include <asm/system.h>
+#include <asm/segment.h>
+
+#if 0
+extern unsigned long RCont;
+
+#define TEST_PAGE(str,adr) \
+ do { \
+ unsigned long flags; \
+ save_flags(flags);; cli(); \
+ if (*(unsigned long *)0xc03ff000 != RCont) { \
+ printk("*0xc03ff000 = %08lx mem_map[]=%d\n", \
+ (RCont = *(unsigned long *)0xc03ff000), \
+ mem_map[MAP_NR(0xc03ff000)] ); \
+ printk("%s ",(str)); \
+ printk("%08lx\n",(unsigned long)(adr)); \
+ } \
+ restore_flags(flags); \
+ } while(0)
+
+#else
+
+#define TEST_PAGE(str,adr) do {} while(0)
+
+#endif
+
+
+#define MAJOR_NR ACSI_MAJOR
+#include "blk.h"
+
+#define DEBUG
+#undef NO_WRITE
+
+#define MAX_ERRORS 8 /* Max read/write errors/sector */
+#define MAX_LUN 8 /* Max LUNs per target */
+#define MAX_DEV 16
+
+#define ACSI_BUFFER_SIZE (16*1024)
+#define ACSI_BUFFER_SECTORS (ACSI_BUFFER_SIZE/512)
+
+#define ACSI_TIMEOUT (4*HZ)
+
+
+typedef enum {
+ NONE, HARDDISK, CDROM
+} ACSI_TYPE;
+
+struct acsi_info_struct {
+ ACSI_TYPE type; /* type of device */
+ unsigned target; /* target number */
+ unsigned lun; /* LUN in target controller */
+ unsigned removable : 1; /* Flag for removable media */
+ unsigned read_only : 1; /* Flag for read only devices */
+ unsigned changed : 1; /* Medium has been changed */
+ unsigned long size; /* #blocks */
+} acsi_info[MAX_DEV];
+
+typedef struct {
+ unsigned long dummy[2];
+ unsigned long sector_size;
+ unsigned char format_code;
+#define SENSE_FORMAT_FIX 1
+#define SENSE_FORMAT_CHNG 2
+ unsigned char cylinders_h;
+ unsigned char cylinders_l;
+ unsigned char heads;
+ unsigned char reduced_h;
+ unsigned char reduced_l;
+ unsigned char precomp_h;
+ unsigned char precomp_l;
+ unsigned char landing_zone;
+ unsigned char steprate;
+ unsigned char type;
+#define SENSE_TYPE_FIXCHNG_MASK 4
+#define SENSE_TYPE_SOFTHARD_MASK 8
+#define SENSE_TYPE_FIX 4
+#define SENSE_TYPE_CHNG 0
+#define SENSE_TYPE_SOFT 0
+#define SENSE_TYPE_HARD 8
+ unsigned char sectors;
+} SENSE_DATA;
+
+#define CAPACITY(sd) (((int)((sd).cylinders_h<<8)|(sd).cylinders_l) * \
+ (sd).heads * \
+ (sd).sectors)
+
+static char *acsi_buffer;
+static unsigned long phys_acsi_buffer;
+static int NDevices = 0;
+static int acsi_sizes[MAX_DEV<<4] = { 0, };
+static int acsi_blocksizes[MAX_DEV<<4] = { 0, };
+static struct hd_struct acsi_part[MAX_DEV<<4] = { {0,0}, };
+static int access_count[MAX_DEV] = { 0, };
+static char busy[MAX_DEV] = { 0, };
+static struct wait_queue *busy_wait;
+
+static int CurrentNReq;
+static int CurrentNSect;
+static char *CurrentBuffer;
+
+
+#define ENABLE_IRQ() \
+ do { \
+ mfp.int_pn_b = 0x7f; \
+ mfp.int_en_b |= 0x80; \
+ } while(0)
+
+#define DISABLE_IRQ() \
+ do { \
+ mfp.int_en_b &= ~0x80; \
+ } while(0)
+
+#define SET_TIMER() \
+ do { \
+ del_timer( &acsi_timer ); \
+ acsi_timer.expires = ACSI_TIMEOUT; \
+ add_timer( &acsi_timer ); \
+ } while(0)
+
+#define CLEAR_TIMER() \
+ do { \
+ del_timer( &acsi_timer ); \
+ } while(0)
+
+#define STRAM_ADDR(a) (((a) & 0xff000000) == 0)
+
+
+
+/* ACSI commands */
+
+static char tur_cmd[6] = { 0x00, 0, 0, 0, 0, 0 };
+static char modesense_cmd[6] = { 0x1a, 0, 0, 0, 24, 0 };
+static char inquiry_cmd[6] = { 0x12, 0, 0, 0, 16, 0 };
+static char reqsense_cmd[6] = { 0x03, 0, 0, 0, 4, 0 };
+static char read_cmd[6] = { 0x08, 0, 0, 0, 0, 0 };
+static char write_cmd[6] = { 0x0a, 0, 0, 0, 0, 0 };
+static char pa_med_rem_cmd[6] = { 0x1e, 0, 0, 0, 0, 0 };
+
+#define CMDSET_TARG_LUN(cmd,targ,lun) \
+ do { \
+ cmd[0] = (cmd[0] & ~0xe0) | (targ)<<5; \
+ cmd[1] = (cmd[1] & ~0xe0) | (lun)<<5; \
+ } while(0)
+
+#define CMDSET_BLOCK(cmd,blk) \
+ do { \
+ unsigned long __blk = (blk); \
+ cmd[3] = __blk; __blk >>= 8; \
+ cmd[2] = __blk; __blk >>= 8; \
+ cmd[1] = (cmd[1] & 0xe0) | (__blk & 0x1f); \
+ } while(0)
+
+#define CMDSET_LEN(cmd,len) \
+ do { \
+ cmd[4] = (len); \
+ } while(0)
+
+#define min(a,b) (((a)<(b))?(a):(b))
+
+
+/* ACSI errors (from REQUEST SENSE) */
+
+struct acsi_error {
+ unsigned char code;
+ const char *text;
+} acsi_errors[] = {
+ { 0x00, "No error (??)" },
+ { 0x01, "No index pulses" },
+ { 0x02, "Seek not complete" },
+ { 0x03, "Write fault" },
+ { 0x04, "Drive not ready" },
+ { 0x06, "No Track 00 signal" },
+ { 0x10, "ECC error in ID field" },
+ { 0x11, "Uncorrectable data error" },
+ { 0x12, "ID field address mark not found" },
+ { 0x13, "Data field address mark not found" },
+ { 0x14, "Record not found" },
+ { 0x15, "Seek error" },
+ { 0x18, "Data check in no retry mode" },
+ { 0x19, "ECC error during verify" },
+ { 0x1a, "Access to bad block" },
+ { 0x1c, "Unformatted or bad format" },
+ { 0x20, "Invalid command" },
+ { 0x21, "Invalid block address" },
+ { 0x23, "Volume overflow" },
+ { 0x24, "Invalid argument" },
+ { 0x25, "Invalid drive number" },
+ { 0x26, "Byte zero parity check" },
+ { 0x28, "Cartride changed" },
+ { 0x2c, "Error count overflow" },
+ { 0x30, "Controller selftest failed" }
+};
+
+
+/***************************** Prototypes *****************************/
+
+static int wait_for_IRQ( unsigned timeout );
+static int wait_for_noIRQ( unsigned timeout );
+static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int
+ rwflag );
+static int acsicmd_nodma( const char *cmd );
+static int acsi_reqsense( char *buffer );
+static int acsi_getstatus( void );
+static void acsi_print_error( const unsigned char *errblk );
+static void acsi_interrupt( struct intframe *fp, void *data );
+static void unexpected_acsi_interrupt( void );
+static void bad_rw_intr( void );
+static void read_intr( void );
+static void write_intr( void);
+static void acsi_times_out( unsigned long dummy );
+static void copy_to_acsibuffer( void );
+static void copy_from_acsibuffer( void );
+static void do_end_requests( void );
+static void do_acsi_request( void );
+static void redo_acsi_request( void );
+static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int
+ cmd, unsigned long arg );
+static int acsi_open( struct inode * inode, struct file * filp );
+static void acsi_release( struct inode * inode, struct file * file );
+static void acsi_prevent_removal( int target, int flag );
+static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd );
+static void acsi_geninit( void );
+int revalidate_acsidisk( int dev, int maxusage );
+
+/************************* End of Prototypes **************************/
+
+
+struct timer_list acsi_timer = { NULL, NULL, 0, 0, acsi_times_out };
+
+
+
+/***********************************************************************
+ *
+ * ACSI primitives
+ *
+ **********************************************************************/
+
+
+/*
+ * The following two functions wait for _IRQ to become Low or High,
+ * resp., with a timeout. The 'timeout' parameter is in jiffies
+ * (10ms).
+ * If the functions are called with timer interrupts on (int level <
+ * 6), the timeout is based on the 'jiffies' variable to provide exact
+ * timeouts for device probing etc.
+ * If interrupts are disabled, the number of tries is based on the
+ * 'loops_per_sec' variable. A rough estimation is sufficient here...
+ */
+
+#define INT_LEVEL \
+ ({ unsigned __sr; \
+ __asm__ __volatile__ ( "movew sr,%0" : "=dm" (__sr) ); \
+ (__sr >> 8) & 7; \
+ })
+
+static int wait_for_IRQ( unsigned timeout )
+
+{
+ if (INT_LEVEL < 6) {
+ unsigned long maxjif;
+ for( maxjif = jiffies + timeout; jiffies < maxjif; )
+ if (!(mfp.par_dt_reg & 0x20)) return( 1 );
+ }
+ else {
+ long tries = loops_per_sec / HZ / 8 * timeout;
+ while( --tries >= 0 )
+ if (!(mfp.par_dt_reg & 0x20)) return( 1 );
+ }
+ return( 0 ); /* timeout! */
+}
+
+
+static int wait_for_noIRQ( unsigned timeout )
+
+{
+ if (INT_LEVEL < 6) {
+ unsigned long maxjif;
+ for( maxjif = jiffies + timeout; jiffies < maxjif; )
+ if (mfp.par_dt_reg & 0x20) return( 1 );
+ }
+ else {
+ long tries = loops_per_sec * timeout / HZ / 8;
+ while( tries-- >= 0 )
+ if (mfp.par_dt_reg & 0x20) return( 1 );
+ }
+ return( 0 ); /* timeout! */
+}
+
+
+/* Send one data byte over the bus and set mode for next operation
+ * with one move.l -- Atari recommends this...
+ */
+
+#define DMA_LONG_WRITE(data,mode) \
+ do { \
+ *((unsigned long *)&dma_wd.fdc_acces_seccount) = ((data)<<16) | (mode); \
+ } while(0)
+
+
+/* acsicmd_dma() sends an ACSI command and sets up the DMA to transfer
+ * 'blocks' blocks of 512 bytes from/to 'buffer'.
+ * Because the _IRQ signal is used for handshaking the command bytes,
+ * the ACSI interrupt has to be disabled in this function. If the end
+ * of the operation should be signalled by a real interrupt, it has to be
+ * reenabled afterwards.
+ */
+
+static int acsicmd_dma( const char *cmd, char *buffer, int blocks, int rwflag )
+
+{ unsigned long flags, paddr;
+ int i;
+
+#ifdef NO_WRITE
+ if (rwflag || *cmd == 0x0a) {
+ printk( "ACSI: Write commands disabled!\n" );
+ return( 0 );
+ }
+#endif
+
+ rwflag = rwflag ? 0x100 : 0;
+ paddr = VTOP( buffer );
+
+ DISABLE_IRQ();
+
+ save_flags(flags);
+ cli();
+ /* Low on A1 */
+ dma_wd.dma_mode_status = 0x88 | rwflag;
+ nop(); nop();
+
+ /* set DMA address */
+ dma_wd.dma_lo = (unsigned char)paddr;
+ paddr >>= 8;
+ nop();
+ dma_wd.dma_md = (unsigned char)paddr;
+ paddr >>= 8;
+ nop();
+ dma_wd.dma_hi = (unsigned char)paddr;
+ nop();
+ restore_flags(flags);
+
+ /* send the command bytes except the last */
+ for( i = 0; i < 5; ++i ) {
+ DMA_LONG_WRITE( *cmd++, 0x8a | rwflag );
+ udelay(20);
+ if (!wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */
+ }
+
+ /* Clear FIFO and switch DMA to correct direction */
+ dma_wd.dma_mode_status = 0x90 | (rwflag ^ 0x100);
+ nop();
+ dma_wd.dma_mode_status = 0x90 | rwflag;
+ nop();
+
+ /* How many sectors for DMA */
+ dma_wd.fdc_acces_seccount = blocks;
+ nop();
+
+ /* send last command byte */
+ dma_wd.dma_mode_status = 0x8a | rwflag;
+ nop();
+ DMA_LONG_WRITE( *cmd++, 0x0a | rwflag );
+ udelay(80);
+
+ return( 1 );
+ /* Note that the ACSI interrupt is still disabled after this
+ * function. If you want to get the IRQ delivered, enable it manually!
+ */
+}
+
+
+/*
+ * acsicmd_nodma() sends an ACSI command that requires no DMA.
+ */
+
+static int acsicmd_nodma( const char *cmd )
+
+{ int i;
+
+ DISABLE_IRQ();
+
+ /* send first command byte */
+ dma_wd.dma_mode_status = 0x88;
+ nop(); nop();
+ DMA_LONG_WRITE( *cmd++, 0x8a );
+ udelay(20);
+ if (!wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */
+
+ /* send the intermediate command bytes */
+ for( i = 0; i < 4; ++i ) {
+ DMA_LONG_WRITE( *cmd++, 0x8a );
+ udelay(20);
+ if (!wait_for_IRQ( HZ/2 )) return( 0 ); /* timeout */
+ }
+
+ /* send last command byte */
+ DMA_LONG_WRITE( *cmd++, 0x0a );
+ udelay(80);
+
+ return( 1 );
+ /* Note that the ACSI interrupt is still disabled after this
+ * function. If you want to get the IRQ delivered, enable it manually!
+ */
+}
+
+
+#ifdef DEBUG
+
+/* REQUEST SENSE is called only when DEBUG is defined to better
+ * specify the error that occured.
+ * Under normal circumstances, the exact error reason doesn't matter
+ * and this function isn't needed.
+ */
+
+static int acsi_reqsense( char *buffer )
+
+{
+ if (!acsicmd_dma( reqsense_cmd, buffer, 1, 0 )) return( 0 );
+ if (!wait_for_IRQ( 10 )) return( 0 );
+ acsi_getstatus();
+ udelay(100);
+ if (!acsicmd_nodma( reqsense_cmd )) return( 0 );
+ if (!wait_for_IRQ( 10 )) return( 0 );
+ acsi_getstatus();
+ udelay(100);
+ if (!acsicmd_nodma( reqsense_cmd )) return( 0 );
+ if (!wait_for_IRQ( 10 )) return( 0 );
+ acsi_getstatus();
+ udelay(100);
+ if (!acsicmd_nodma( reqsense_cmd )) return( 0 );
+ if (!wait_for_IRQ( 10 )) return( 0 );
+ acsi_getstatus();
+ cache_clear( VTOP(buffer), 16 );
+
+ return( 1 );
+}
+
+#endif
+
+
+/*
+ * ACSI status phase: get the status byte from the bus
+ *
+ * I've seen several times that a 0xff status is read, propably due to
+ * a timing error. In this case, the procedure is repeated after the
+ * next _IRQ edge.
+ */
+
+static int acsi_getstatus( void )
+
+{ int status;
+
+ for(;;) {
+ if (!wait_for_IRQ( 40 )) return( -1 );
+ dma_wd.dma_mode_status = 0x8a;
+ nop(); nop();
+ status = dma_wd.fdc_acces_seccount;
+ if (status != 0xff) break;
+#ifdef DEBUG
+ printk("ACSI: skipping 0xff status byte\n" );
+#endif
+ udelay(40);
+ wait_for_noIRQ( 20 );
+ }
+ dma_wd.dma_mode_status = 0x80;
+ udelay(40);
+ wait_for_noIRQ( 20 );
+
+ return( status & 0x1f ); /* mask of the device# */
+}
+
+
+#if 0
+
+/* Receive data in an extended status phase. Never needed... */
+
+static int acsi_extstatus( char *buffer, int cnt )
+
+{ int status, i = 0;
+
+ udelay(80);
+ while( cnt-- >= 0 ) {
+ if (!wait_for_IRQ( 40 )) return( 0 );
+ dma_wd.dma_mode_status = 0x8a;
+ nop(); nop();
+ status = dma_wd.fdc_acces_seccount;
+ *buffer++ = status & 0xff;
+ udelay(80);
+ }
+ return( 1 );
+}
+
+#endif
+
+
+static void acsi_print_error( const unsigned char *errblk )
+
+{ int i, errcode = errblk[0] & 0x7f;
+
+ printk( "ACSI error 0x%02x", errcode );
+ if (errblk[0] & 0x80)
+ printk( " for sector %d",
+ ((errblk[1] & 0x1f) << 16) |
+ (errblk[2] << 8) | errblk[0] );
+ for( i = sizeof(acsi_errors)/sizeof(*acsi_errors)-1; i >= 0; --i )
+ if (acsi_errors[i].code == errcode) break;
+ if (i >= 0)
+ printk( ": %s\n", acsi_errors[i].text );
+}
+
+
+
+
+/*******************************************************************
+ *
+ * ACSI interrupt routine
+ * Test, if this is a ACSI interrupt and call the irq handler
+ * Otherwise ignore this interrupt.
+ *
+ *******************************************************************/
+
+static void acsi_interrupt( struct intframe *fp, void *data )
+
+{ void (*acsi_irq_handler)(void) = DEVICE_INTR;
+
+ DEVICE_INTR = NULL;
+ CLEAR_TIMER();
+
+ if (!acsi_irq_handler)
+ acsi_irq_handler = unexpected_acsi_interrupt;
+ acsi_irq_handler();
+}
+
+
+/******************************************************************
+ *
+ * The Interrupt handlers
+ *
+ *******************************************************************/
+
+
+static void unexpected_acsi_interrupt( void )
+
+{
+ printk("Unexpected ACSI interrupt\n");
+}
+
+
+/* This function is called in case of errors. Because we cannot reset
+ * the ACSI bus or a single device, there is no other choice than
+ * retrying several times :-(
+ */
+
+static void bad_rw_intr( void )
+
+{
+ if (!CURRENT)
+ return;
+
+ if (++CURRENT->errors >= MAX_ERRORS)
+ end_request(0);
+ /* Otherwise just retry */
+}
+
+
+static void read_intr( void )
+
+{ int status;
+
+ status = acsi_getstatus();
+ if (status != 0) {
+ printk( "ad%c: ", DEVICE_NR(MINOR(CURRENT->dev))+'a' );
+ if (!acsi_reqsense( acsi_buffer ))
+ printk( "ACSI error and REQUEST SENSE failed (status=0x%02x)\n", status );
+ else {
+ acsi_print_error( acsi_buffer );
+ if ((*acsi_buffer & 0x7f) == 0x28)
+ acsi_info[DEVICE_NR(MINOR(CURRENT->dev))].changed = 1;
+ }
+ ENABLE_IRQ();
+ bad_rw_intr();
+ redo_acsi_request();
+ return;
+ }
+
+ cache_clear( VTOP(CurrentBuffer), CurrentNSect*512 );
+ if (CurrentBuffer == acsi_buffer)
+ copy_from_acsibuffer();
+
+ do_end_requests();
+ redo_acsi_request();
+}
+
+
+static void write_intr(void)
+
+{ int status;
+
+ status = acsi_getstatus();
+ if (status != 0) {
+ printk( "ad%c: ", DEVICE_NR(MINOR(CURRENT->dev))+'a' );
+ if (!acsi_reqsense( acsi_buffer ))
+ printk( "ACSI error and REQUEST SENSE failed (status=0x%02x)\n", status );
+ else {
+ acsi_print_error( acsi_buffer );
+ if ((*acsi_buffer & 0x7f) == 0x28)
+ acsi_info[DEVICE_NR(MINOR(CURRENT->dev))].changed = 1;
+ }
+ bad_rw_intr();
+ redo_acsi_request();
+ return;
+ }
+
+ do_end_requests();
+ redo_acsi_request();
+}
+
+
+static void acsi_times_out( unsigned long dummy )
+
+{
+ DEVICE_INTR = NULL;
+ printk("ACSI timeout\n");
+ if (!CURRENT) return;
+ if (++CURRENT->errors >= MAX_ERRORS) {
+#ifdef DEBUG
+ printk("ACSI: too many errors.\n");
+#endif
+ end_request(0);
+ }
+
+ redo_acsi_request();
+}
+
+
+
+/***********************************************************************
+ *
+ * Scatter-gather utility functions
+ *
+ ***********************************************************************/
+
+
+static void copy_to_acsibuffer( void )
+
+{ int i;
+ char *src, *dst;
+ struct buffer_head *bh;
+
+ src = CURRENT->buffer;
+ dst = acsi_buffer;
+ bh = CURRENT->bh;
+
+ if (!bh)
+ memcpy( dst, src, CurrentNSect*512 );
+ else
+ for( i = 0; i < CurrentNReq; ++i ) {
+ memcpy( dst, src, bh->b_size );
+ dst += bh->b_size;
+ if ((bh = bh->b_reqnext))
+ src = bh->b_data;
+ }
+}
+
+
+static void copy_from_acsibuffer( void )
+
+{ int i;
+ char *src, *dst;
+ struct buffer_head *bh;
+
+ dst = CURRENT->buffer;
+ src = acsi_buffer;
+ bh = CURRENT->bh;
+
+ if (!bh)
+ memcpy( dst, src, CurrentNSect*512 );
+ else
+ for( i = 0; i < CurrentNReq; ++i ) {
+ memcpy( dst, src, bh->b_size );
+ src += bh->b_size;
+ if ((bh = bh->b_reqnext))
+ dst = bh->b_data;
+ }
+}
+
+
+static void do_end_requests( void )
+
+{ int i, n;
+
+ if (!CURRENT->bh) {
+ CURRENT->nr_sectors -= CurrentNSect;
+ CURRENT->current_nr_sectors -= CurrentNSect;
+ CURRENT->sector += CurrentNSect;
+ if (CURRENT->nr_sectors == 0)
+ end_request(1);
+ }
+ else {
+ for( i = 0; i < CurrentNReq; ++i ) {
+ n = CURRENT->bh->b_size >> 9;
+ CURRENT->nr_sectors -= n;
+ CURRENT->current_nr_sectors -= n;
+ CURRENT->sector += n;
+ end_request(1);
+ }
+ }
+}
+
+
+
+
+/***********************************************************************
+ *
+ * do_acsi_request and friends
+ *
+ ***********************************************************************/
+
+static void do_acsi_request( void )
+
+{
+ stdma_lock( acsi_interrupt, NULL );
+ redo_acsi_request();
+}
+
+
+static void redo_acsi_request( void )
+
+{ unsigned block, dev, target, lun, nsect;
+ char *buffer;
+ unsigned long pbuffer;
+ struct buffer_head *bh;
+
+ TEST_PAGE("redo_acsi_request",0);
+
+ if (CURRENT && CURRENT->dev < 0) {
+ if (!DEVICE_INTR) stdma_release();
+ return;
+ }
+
+ if (DEVICE_INTR)
+ return;
+
+ repeat:
+ CLEAR_TIMER();
+ /* Another check here: An interrupt or timer event could have
+ * happened since the last check!
+ */
+ if (CURRENT && CURRENT->dev < 0) {
+ if (!DEVICE_INTR) stdma_release();
+ return;
+ }
+ if (DEVICE_INTR)
+ return;
+
+ if (!CURRENT) {
+ CLEAR_INTR;
+ stdma_release();
+ return;
+ }
+
+ if (MAJOR(CURRENT->dev) != MAJOR_NR)
+ panic(DEVICE_NAME ": request list destroyed");
+ if (CURRENT->bh) {
+ if (!CURRENT->bh->b_lock)
+ panic(DEVICE_NAME ": block not locked");
+ }
+
+ dev = MINOR(CURRENT->dev);
+ block = CURRENT->sector;
+ if (DEVICE_NR(dev) >= NDevices ||
+ block+CURRENT->nr_sectors >= acsi_part[dev].nr_sects) {
+#ifdef DEBUG
+ printk( "ad%c: attempted access for block %d past end of device at block %ld.\n",
+ DEVICE_NR(dev)+'a', block, acsi_part[dev].nr_sects);
+#endif
+ end_request(0);
+ goto repeat;
+ }
+ if (acsi_info[DEVICE_NR(dev)].changed) {
+ printk( "ad%c: request denied because cartridge has been changed.\n",
+ DEVICE_NR(dev)+'a' );
+ end_request(0);
+ goto repeat;
+ }
+
+ block += acsi_part[dev].start_sect;
+ target = acsi_info[DEVICE_NR(dev)].target;
+ lun = acsi_info[DEVICE_NR(dev)].lun;
+
+ /* Find out how many sectors should be transferred from/to
+ * consecutive buffers and thus can be done with a single command.
+ */
+ buffer = CURRENT->buffer;
+ pbuffer = VTOP(buffer);
+ nsect = CURRENT->current_nr_sectors;
+ CurrentNReq = 1;
+
+ if ((bh = CURRENT->bh) && bh != CURRENT->bhtail) {
+ if (!STRAM_ADDR(pbuffer)) {
+ /* If transfer is done via the ACSI buffer anyway, we can
+ * assemble as much bh's as fit in the buffer.
+ */
+ while( (bh = bh->b_reqnext) ) {
+ if (nsect + (bh->b_size>>9) > ACSI_BUFFER_SECTORS) break;
+ nsect += bh->b_size >> 9;
+ ++CurrentNReq;
+ if (bh == CURRENT->bhtail) break;
+ }
+ buffer = acsi_buffer;
+ }
+ else {
+ unsigned long pendadr, pnewadr;
+ pendadr = pbuffer + nsect*512;
+ while( (bh = bh->b_reqnext) ) {
+ pnewadr = VTOP(bh->b_data);
+ if (!STRAM_ADDR(pnewadr) || pendadr != pnewadr) break;
+ nsect += bh->b_size >> 9;
+ pendadr += pnewadr + bh->b_size;
+ ++CurrentNReq;
+ if (bh == CURRENT->bhtail) break;
+ }
+ }
+ }
+ else {
+ if (!STRAM_ADDR(pbuffer)) {
+ buffer = acsi_buffer;
+ if (nsect > ACSI_BUFFER_SECTORS)
+ nsect = ACSI_BUFFER_SECTORS;
+ }
+ }
+ CurrentBuffer = buffer;
+ CurrentNSect = nsect;
+
+ if (CURRENT->cmd == WRITE) {
+ CMDSET_TARG_LUN( write_cmd, target, lun );
+ CMDSET_BLOCK( write_cmd, block );
+ CMDSET_LEN( write_cmd, nsect );
+ if (buffer == acsi_buffer)
+ copy_to_acsibuffer();
+ cache_push( pbuffer, nsect*512 );
+ if (!acsicmd_dma( write_cmd, buffer, nsect, 1 )) {
+ printk( "ACSI: Timeout in command block\n" );
+ udelay(200); /* wait some time between commands to let
+ * things settle down... */
+ bad_rw_intr();
+ goto repeat;
+ }
+ SET_INTR(write_intr);
+ SET_TIMER();
+ ENABLE_IRQ();
+ return;
+ }
+ if (CURRENT->cmd == READ) {
+ CMDSET_TARG_LUN( read_cmd, target, lun );
+ CMDSET_BLOCK( read_cmd, block );
+ CMDSET_LEN( read_cmd, nsect );
+ if (!acsicmd_dma( read_cmd, buffer, nsect, 0 )) {
+ printk( "ACSI: Timeout in command block\n" );
+ udelay(200); /* wait some time between commands to let
+ * things settle down... */
+ bad_rw_intr();
+ goto repeat;
+ }
+ SET_INTR(read_intr);
+ SET_TIMER();
+ ENABLE_IRQ();
+ return;
+ }
+ panic("unknown ACSI command");
+}
+
+
+
+/***********************************************************************
+ *
+ * Misc functions: ioctl, open, release, check_change, ...
+ *
+ ***********************************************************************/
+
+
+static int acsi_ioctl( struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg )
+{ int dev, err;
+
+ if (!inode)
+ return -EINVAL;
+ dev = DEVICE_NR(MINOR(inode->i_rdev));
+ if (dev >= NDevices)
+ return -EINVAL;
+ switch (cmd) {
+ /* I left out the GETGEO cmd; This doesn't make much sense for
+ * ACSI disks...
+ */
+ case BLKGETSIZE: /* Return device size */
+ if (!arg) return -EINVAL;
+ err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
+ if (err)
+ return err;
+ put_fs_long(acsi_part[MINOR(inode->i_rdev)].nr_sects,
+ (long *) arg);
+ return 0;
+ case BLKFLSBUF:
+ if(!suser()) return -EACCES;
+ if(!inode->i_rdev) return -EINVAL;
+ fsync_dev(inode->i_rdev);
+ invalidate_buffers(inode->i_rdev);
+ return 0;
+
+ case BLKRRPART: /* Re-read partition tables */
+ return revalidate_acsidisk(inode->i_rdev, 1);
+ RO_IOCTLS(inode->i_rdev,arg);
+ default:
+ return -EINVAL;
+ }
+}
+
+
+/*
+ * Open a device, check for read-only and lock the medium if it is
+ * removable.
+ */
+
+static int acsi_open( struct inode * inode, struct file * filp )
+
+{ int target;
+ target = DEVICE_NR(MINOR(inode->i_rdev));
+
+ while (busy[target])
+ sleep_on(&busy_wait);
+
+ if (access_count[target] == 0 && acsi_info[target].removable) {
+ check_disk_change( inode->i_rdev );
+ acsi_prevent_removal( target, 1 );
+ }
+ access_count[target]++;
+
+ if (filp && filp->f_mode) {
+ if (filp->f_mode & 2) {
+ if (acsi_info[target].read_only) {
+ acsi_release( inode, filp );
+ return( -EACCES );
+ }
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Releasing a block device means we sync() it, so that it can safely
+ * be forgotten about...
+ */
+
+static void acsi_release( struct inode * inode, struct file * file )
+
+{ int target;
+
+ sync_dev(inode->i_rdev);
+
+ target = DEVICE_NR(MINOR(inode->i_rdev));
+ if (--access_count[target] == 0 && acsi_info[target].removable)
+ acsi_prevent_removal( target, 0 );
+}
+
+
+/*
+ * Prevent or allow a media change for removable devices.
+ */
+
+static void acsi_prevent_removal( int target, int flag )
+
+{
+ stdma_lock( NULL, NULL );
+
+ CMDSET_TARG_LUN( pa_med_rem_cmd,
+ acsi_info[target].target,
+ acsi_info[target].lun );
+ CMDSET_LEN( pa_med_rem_cmd, flag );
+
+ if (!acsicmd_nodma( pa_med_rem_cmd )) goto the_end;
+ if (!wait_for_IRQ( 3*HZ )) goto the_end;
+ acsi_getstatus();
+ /* Do not report errors -- some devices may not know this command. */
+
+ the_end:
+ ENABLE_IRQ();
+ stdma_release();
+}
+
+
+int check_acsi_media_change( int full_dev, int flag )
+
+{ int target = DEVICE_NR(MINOR(full_dev));
+
+ if (!acsi_info[target].removable) return( 0 );
+
+ if (acsi_info[target].changed)
+ /* We can be sure that the medium has been changed -- REQUEST
+ * SENSE has reported this earlier.
+ */
+ return( 1 );
+
+ /* If the flag isn't set, make a test by reading block 0.
+ * If errors happen, it seems to be better to say "changed"...
+ */
+ stdma_lock( NULL, NULL );
+ CMDSET_TARG_LUN( read_cmd, acsi_info[target].target, acsi_info[target].lun );
+ CMDSET_BLOCK( read_cmd, 0 );
+ CMDSET_LEN( read_cmd, 1 );
+ if (acsicmd_dma( read_cmd, acsi_buffer, 1, 0 ) &&
+ wait_for_IRQ( HZ )) {
+ if (acsi_getstatus()) {
+ if (acsi_reqsense( acsi_buffer )) {
+ if ((acsi_buffer[0] & 0x7f) == 0x28)
+ acsi_info[target].changed = 1;
+ }
+ else {
+ printk( "ad%c: REQUEST SENSE failed in test for medium change; assuming a change\n",
+ target+'a' );
+ acsi_info[target].changed = 1;
+ }
+ }
+ }
+ else {
+ printk( "ad%c: Test for medium changed timed out; assuming a change\n",
+ target+'a' );
+ acsi_info[target].changed = 1;
+ }
+ ENABLE_IRQ();
+ stdma_release();
+
+ /* Now, after reading a block, the changed status is surely valid. */
+ return( acsi_info[target].changed );
+}
+
+
+static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd )
+
+{
+ CMDSET_TARG_LUN( modesense_cmd, target, lun );
+ if (!acsicmd_dma( modesense_cmd, acsi_buffer, 1, 0 ) ||
+ !wait_for_IRQ( 3*HZ ) ||
+ acsi_getstatus() != 0 ||
+ /* read twice to jump over the second 16-byte border! */
+ (udelay(300), !wait_for_noIRQ( 20 )) ||
+ !acsicmd_nodma( modesense_cmd ) ||
+ !wait_for_IRQ( 3*HZ ) ||
+ acsi_getstatus() != 0) {
+ return( 0 );
+ }
+
+ cache_clear( phys_acsi_buffer, sizeof(SENSE_DATA) );
+ *sd = *(SENSE_DATA *)acsi_buffer;
+ if (CAPACITY(*sd) == 0) {
+#ifdef DEBUG
+ int i;
+ printk( "Mode sense data for ACSI target %d, lun %d seem not valid:",
+ target, lun );
+ for( i = 0; i < sizeof(SENSE_DATA); ++i )
+ printk( "%02x ", (unsigned char)acsi_buffer[i] );
+ printk( "\n" );
+#endif
+ return( 0 );
+ }
+ return( 1 );
+}
+
+
+
+/*******************************************************************
+ *
+ * Initialization
+ *
+ ********************************************************************/
+
+
+static struct gendisk acsi_gendisk = {
+ MAJOR_NR, /* Major number */
+ "ad", /* Major name */
+ 4, /* Bits to shift to get real from partition */
+ 1 << 4, /* Number of partitions per real */
+ MAX_DEV, /* maximum number of real */
+ acsi_geninit, /* init function */
+ acsi_part, /* hd struct */
+ acsi_sizes, /* block sizes */
+ 0, /* number */
+ (void *)acsi_info, /* internal */
+ NULL /* next */
+};
+
+
+static void acsi_geninit( void )
+
+{ int i;
+ int target, lun, status;
+ ACSI_TYPE type;
+ int rmf, rdonly, got_inquiry;
+ SENSE_DATA sense;
+ unsigned long size;
+
+ printk ("Probing ACSI devices:\n");
+ NDevices = 0;
+ stdma_lock( NULL, NULL );
+
+ for( target = 0; target < 8 && NDevices < MAX_DEV; ++target ) {
+
+ lun = 0;
+ repeat_for_lun:
+
+ /* Do a TEST UNIT READY command to test the presence of a
+ * device
+ */
+ CMDSET_TARG_LUN( tur_cmd, target, lun );
+ if (!acsicmd_nodma( tur_cmd ))
+ /* timed out -> no device here */
+ continue;
+ status = acsi_getstatus();
+ if (status) {
+ if (status == 0x12)
+ /* The SLM printer should be the only device that
+ * responds with the error code in the status byte. In
+ * correct status bytes, bit 4 is never set.
+ */
+ printk( " ID %d, LUN %d: SLM printer (not supported)\n",
+ target, lun );
+ continue;
+ }
+
+ /* Assume default values */
+ type = HARDDISK;
+ rmf = 0;
+ rdonly = 0;
+ got_inquiry = 0;
+ printk( " ID %d, LUN %d: ", target, lun );
+
+ /* Do an INQUIRY command to get more infos on this device;
+ * some older Atari disks don't know about INQUIRY, so use the
+ * defaults above in case of error...
+ */
+ udelay(200);
+ CMDSET_TARG_LUN( inquiry_cmd, target, lun );
+ if (acsicmd_dma( inquiry_cmd, acsi_buffer, 1, 0 ) &&
+ acsi_getstatus() == 0) {
+
+ cache_clear( phys_acsi_buffer, 32 );
+
+ switch( acsi_buffer[0] ) {
+ case 0:
+ break;
+ case 5:
+ type = CDROM;
+ rdonly = 1;
+ break;
+ default:
+ printk( "Device type not supported (%d)\n", acsi_buffer[0] );
+ continue;
+ }
+ rmf = !!(acsi_buffer[1] & 0x80); /* removable? */
+ got_inquiry = 1;
+ }
+
+ udelay(200);
+ if (!acsi_mode_sense( target, lun, &sense )) {
+ printk( "No mode sense data.\n" );
+ continue;
+ }
+ if (sense.sector_size != 512) {
+ printk( "Sector size != 512 not supported.\n" );
+ continue;
+ }
+ size = CAPACITY(sense);
+ if (!got_inquiry) {
+ /* If INQUIRY wasn't successful, determine the type from
+ * the sense data.
+ */
+ if (sense.format_code == SENSE_FORMAT_CHNG &&
+ (sense.type & SENSE_TYPE_FIXCHNG_MASK) == SENSE_TYPE_CHNG)
+ rmf = 1;
+ }
+
+#if 0
+ /* Read sector 0 (the root sector) to get the media size.
+ * !! This has to be replaced by some better method! This data
+ * is only valid for Atari partitioned disks!
+ */
+ udelay(200);
+ CMDSET_TARG_LUN( read_cmd, target, lun );
+ CMDSET_BLOCK( read_cmd, 0 );
+ CMDSET_LEN( read_cmd, 1 );
+ if (!acsicmd_dma( read_cmd, acsi_buffer, 1, 0 ) ||
+ !wait_for_IRQ( 3*HZ ) ||
+ acsi_getstatus() != 0) {
+ printk( "Unreadable\n" );
+ continue;
+ }
+ cache_clear( phys_acsi_buffer, 512 );
+ size = ((struct rootsector *)acsi_buffer)->hd_siz;
+#endif
+
+ /* Fill in the acsi_info for this device... */
+ acsi_info[NDevices].type = type;
+ acsi_info[NDevices].target = target;
+ acsi_info[NDevices].lun = lun;
+ acsi_info[NDevices].removable = rmf;
+ acsi_info[NDevices].read_only = rdonly;
+ acsi_info[NDevices].changed = 0;
+ acsi_info[NDevices].size = size;
+
+ /* ...and inform the user about it. */
+ switch( type ) {
+ case HARDDISK:
+ printk( "Harddisk " );
+ break;
+ case CDROM:
+ printk( "CD-ROM " );
+ break;
+ default:
+ printk( "Type %d ", (int)type );
+ break;
+ }
+ if (rmf) printk( "(removable) " );
+ if (rdonly) printk( "(read-only) " );
+ printk( "%ld MByte\n", (size*512+1024*1024/2)/(1024*1024) );
+
+ NDevices++;
+
+ /* If a test for this target was successful, try the next LUN, too */
+ if (++lun < MAX_LUN)
+ goto repeat_for_lun;
+ }
+
+ /* reenable interrupt */
+ ENABLE_IRQ();
+ stdma_release();
+
+ printk( "Found %d ACSI device(s) total.\n", NDevices );
+
+ for( i = 0; i < NDevices; ++i ) {
+ acsi_part[i<<4].start_sect = 0;
+ acsi_part[i<<4].nr_sects = acsi_info[i].size;
+ }
+ acsi_gendisk.nr_real = NDevices;
+ for( i = 0; i < (MAX_DEV << 4); i++ )
+ acsi_blocksizes[i] = 1024;
+ blksize_size[MAJOR_NR] = acsi_blocksizes;
+}
+
+
+static struct file_operations acsi_fops = {
+ NULL, /* lseek - default */
+ block_read, /* read - general block-dev read */
+ block_write, /* write - general block-dev write */
+ NULL, /* readdir - bad */
+ NULL, /* select */
+ acsi_ioctl, /* ioctl */
+ NULL, /* mmap */
+ acsi_open, /* open */
+ acsi_release, /* release */
+ block_fsync /* fsync */
+};
+
+
+unsigned long acsi_init( unsigned long mem_start, unsigned long mem_end )
+
+{
+ if (boot_info.machtype != MACH_ATARI ||
+ boot_info.bi_atari.model == ATARI_FALCON)
+ /* Do not init ACSI on a Falcon -- the port is used for SCSI there! */
+ return( mem_start );
+
+ if (register_blkdev( MAJOR_NR, "ad", &acsi_fops )) {
+ printk( "Unable to get major %d for ACSI\n", MAJOR_NR );
+ return( mem_start );
+ }
+
+ if (!(acsi_buffer = atari_stram_alloc( ACSI_BUFFER_SIZE, &mem_start ))) {
+ printk( "Unable to get ACSI ST-Ram buffer.\n" );
+ return( mem_start );
+ }
+ phys_acsi_buffer = VTOP( acsi_buffer );
+
+ blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+ read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */
+ acsi_gendisk.next = gendisk_head;
+ gendisk_head = &acsi_gendisk;
+
+ return( mem_start );
+}
+
+
+#define DEVICE_BUSY busy[target]
+#define USAGE access_count[target]
+#define GENDISK_STRUCT acsi_gendisk
+
+/*
+ * This routine is called to flush all partitions and partition tables
+ * for a changed scsi disk, and then re-read the new partition table.
+ * If we are revalidating a disk because of a media change, then we
+ * enter with usage == 0. If we are using an ioctl, we automatically have
+ * usage == 1 (we need an open channel to use an ioctl :-), so this
+ * is our limit.
+ */
+
+int revalidate_acsidisk( int dev, int maxusage )
+
+{ int target, major;
+ struct gendisk * gdev;
+ int max_p;
+ int start;
+ int i;
+ SENSE_DATA sense;
+
+ target = DEVICE_NR(MINOR(dev));
+ gdev = &GENDISK_STRUCT;
+
+ cli();
+ if (DEVICE_BUSY || USAGE > maxusage) {
+ sti();
+ return -EBUSY;
+ };
+ DEVICE_BUSY = 1;
+ sti();
+
+ max_p = gdev->max_p;
+ start = target << gdev->minor_shift;
+ major = MAJOR_NR << 8;
+
+ for( i = max_p - 1; i >= 0 ; i-- ) {
+ sync_dev( major | start | i );
+ invalidate_inodes( major | start | i );
+ invalidate_buffers( major | start | i );
+ gdev->part[start+i].start_sect = 0;
+ gdev->part[start+i].nr_sects = 0;
+ };
+
+#if 0
+ /* Read sector 0 and look into the partitioning data to get the
+ * device size.
+ * !! This has to be replaced sometimes by a better method!
+ * Not all devices must be partitioned in Atari format!
+ */
+ bh = bread( dev, 0, 1024 );
+ if (!bh) {
+ printk( "ACSI device %04x: unable to read root sector\n", dev );
+ acsi_info[target].size = 0x1fffff;
+ }
+ else {
+ acsi_info[target].size = ((struct rootsector *)bh->b_data)->hd_siz;
+ brelse( bh );
+ }
+#else
+ stdma_lock( NULL, NULL );
+ if (!acsi_mode_sense( acsi_info[target].target, acsi_info[target].lun, &sense )) {
+ printk( "ACSI device %04x: mode sense failed.\n", dev );
+ acsi_info[target].size = 0x1fffff;
+ }
+ else {
+ acsi_info[target].size = CAPACITY(sense);
+ }
+ ENABLE_IRQ();
+ stdma_release();
+#endif
+
+ acsi_info[target].changed = 0;
+
+ gdev->part[start].nr_sects = acsi_info[target].size;
+ resetup_one_dev( gdev, target );
+
+ DEVICE_BUSY = 0;
+ wake_up(&busy_wait);
+ return 0;
+}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/block/amiflop.c linux-0.9pl4/drivers/block/amiflop.c
--- linux-0.9pl3/drivers/block/amiflop.c Mon Aug 15 19:20:24 1994
+++ linux-0.9pl4/drivers/block/amiflop.c Sat Nov 12 11:35:00 1994
@@ -44,8 +44,8 @@
*/
#define FD_NODRIVE 0x00000000 /* response when no unit is present */
#define FD_DD_3 0xffffffff /* double-density 3.5" (880K) drive */
-#define FD_HD_3 0xaaaaaaaa /* high-density 3.5" (1760K) drive */
-#define FD_DD_5 0x55555555 /* double-density 5.25" (440K) drive */
+#define FD_HD_3 0x55555555 /* high-density 3.5" (1760K) drive */
+#define FD_DD_5 0xaaaaaaaa /* double-density 5.25" (440K) drive */
/*
@@ -87,6 +87,8 @@
/* track buffer */
static int savedtrack = -1;
+static int writepending = 0;
+static int writefromint = 0;
static unsigned char trackdata[MAX_SECTORS * 512];
static char *raw_buf;
@@ -104,10 +106,6 @@
static struct wait_queue *fdc_wait = NULL;
static struct wait_queue *motor_wait = NULL;
-#if 0
-static unsigned int changed_floppies = 0;
-#endif
-
/*
* Functions
*/
@@ -138,6 +136,8 @@
restore_flags(flags);
}
+static struct timer_list flush_track_timer;
+
static struct timer_list motor_on_timer;
static struct timer_list motor_off_timer[FD_MAX_UNITS];
static int on_attempts;
@@ -623,6 +623,8 @@
unit[drive].track = -1;
selected = -1;
savedtrack = -1;
+ writepending = 0; /* if this was true before, too bad! */
+ writefromint = 0;
return 1;
}
return 0;
@@ -688,13 +690,15 @@
custom.dsklen = len/sizeof(short) | DSKLEN_DMAEN|DSKLEN_WRITE;
block_flag = 2;
- while (block_flag == 2)
- sleep_on (&wait_fd_block);
+ return 1;
+}
+static void post_write (void)
+{
udelay (2000); /* 2ms post-write delay */
custom.dsklen = 0;
-
- return 1;
+ writepending = 0;
+ writefromint = 0;
}
static int get_track(int drive, int track)
@@ -719,12 +723,39 @@
}
}
+static void flush_track_callback(unsigned long nr)
+{
+ writefromint = 1;
+ amiga_write(nr, (unsigned long)raw_buf, trackdata, savedtrack);
+ if (!raw_write(nr, savedtrack, raw_buf, unit[nr].type->write_size)) {
+ printk ("floppy disk write protected\n");
+ writefromint = 0;
+ writepending = 0;
+ }
+}
+
+static int non_int_flush_track (unsigned long nr)
+{
+ writefromint = 0;
+ amiga_write(nr, (unsigned long)raw_buf, trackdata, savedtrack);
+ if (!raw_write(nr, savedtrack, raw_buf, unit[nr].type->write_size)) {
+ printk ("floppy disk write protected in write!\n");
+ writepending = 0;
+ return 0;
+ }
+ while (block_flag == 2)
+ sleep_on (&wait_fd_block);
+ post_write();
+ return 1;
+}
+
static void redo_fd_request(void)
{
unsigned int block, track, sector;
int device, drive, cnt;
struct floppy_struct *floppy;
char *data;
+ unsigned long flags;
if (CURRENT && CURRENT->dev < 0) return;
@@ -760,6 +791,18 @@
floppy = unit + drive;
}
+ save_flags (flags);
+ cli();
+ if (drive != selected && writepending) {
+ del_timer (&flush_track_timer);
+ restore_flags (flags);
+ if (!non_int_flush_track (selected)) {
+ end_request(0);
+ goto repeat;
+ }
+ } else
+ restore_flags (flags);
+
for (cnt = 0; cnt < 2; cnt++) {
block = CURRENT->sector + cnt;
if ((int)block > floppy->blocks) {
@@ -771,6 +814,18 @@
sector = block - track * floppy->dtype->sects;
data = CURRENT->buffer + 512 * cnt;
+ save_flags (flags);
+ cli();
+ if (track != savedtrack && writepending) {
+ del_timer (&flush_track_timer);
+ restore_flags (flags);
+ if (!non_int_flush_track (selected)) {
+ end_request(0);
+ goto repeat;
+ }
+ } else
+ restore_flags (flags);
+
switch (CURRENT->cmd) {
case READ:
if (!motor_on (drive)) {
@@ -804,16 +859,22 @@
goto repeat;
}
copy_buffer(data, trackdata + sector * 512);
- if (cnt == 1 || track != ((block+1)/floppy->dtype->sects)) {
- amiga_write(drive, (unsigned long)raw_buf,
- trackdata, track);
- if (!raw_write(drive, track, raw_buf,
- unit[drive].type->write_size)) {
- printk ("floppy disk write protected\n");
- end_request(0);
- goto repeat;
- }
- }
+ /*
+ * setup a callback to write the track buffer
+ * after a short (1 tick) delay.
+ */
+ save_flags (flags);
+ cli();
+
+ if (writepending)
+ /* reset the timer */
+ del_timer (&flush_track_timer);
+
+ writepending = 1;
+ flush_track_timer.data = drive;
+ flush_track_timer.expires = 1;
+ add_timer (&flush_track_timer);
+ restore_flags (flags);
break;
default:
@@ -942,7 +1003,7 @@
printk("Probing floppy drive(s):\n");
for (drive = 0; drive < FD_MAX_UNITS; drive++) {
fd_probe(drive);
- if (unit[drive].type != FD_NODRIVE)
+ if (unit[drive].type->code != FD_NODRIVE)
printk("Unit %d: %s\n", drive, unit[drive].type->name);
}
}
@@ -989,7 +1050,18 @@
static void floppy_release(struct inode * inode, struct file * filp)
{
+ unsigned long flags;
+
sync_dev(inode->i_rdev);
+ save_flags (flags);
+ cli();
+ if ((inode->i_rdev & 3) == selected && writepending) {
+ del_timer (&flush_track_timer);
+ restore_flags (flags);
+ non_int_flush_track (selected);
+ } else
+ restore_flags (flags);
+
if (!fd_ref[inode->i_rdev & 3]--) {
printk("floppy_release with fd_ref == 0");
fd_ref[inode->i_rdev & 3] = 0;
@@ -1013,9 +1085,18 @@
{
if (block_flag)
custom.dsklen = 0x4000;
- block_flag = 0;
+ block_flag = 0;
wake_up (&wait_fd_block);
+
+ if (writefromint) {
+ /*
+ * if it was a write from an interrupt,
+ * we will call post_write from here
+ */
+ post_write ();
+ }
+
}
void amiga_floppy_init(void)
@@ -1043,6 +1124,12 @@
unit[i].track = -1;
}
+ flush_track_timer.next = NULL;
+ flush_track_timer.prev = NULL;
+ flush_track_timer.expires = 0;
+ flush_track_timer.data = 0;
+ flush_track_timer.function = flush_track_callback;
+
/* blk_size[MAJOR_NR] = floppy_sizes; */
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/block/amihd.c linux-0.9pl4/drivers/block/amihd.c
--- linux-0.9pl3/drivers/block/amihd.c Sun Aug 28 17:24:18 1994
+++ linux-0.9pl4/drivers/block/amihd.c Thu Nov 24 20:52:37 1994
@@ -18,6 +18,8 @@
*
*
* Modified 1994 for A4000/40 IDE controller support by Torsten Ebeling
+ *
+ * Modified 16-Nov-1994 to add A1200 IDE controller support by Dwight Engen
*/
/*
@@ -70,7 +72,11 @@
struct hd_i_struct {
unsigned int head,sect,cyl,wpcom,lzone,ctl;
};
+struct hd_regs_struct {
+ unsigned char *hd_data, *hd_error, *hd_nsector, *hd_sector, *hd_lcyl,
+ *hd_hcyl, *hd_current, *hd_status, *hd_cmd; };
static struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
+static struct hd_regs_struct hd_regs;
static int NR_HD = 0;
static struct hd_struct hd[MAX_HD<<6]={{0,0},};
@@ -100,7 +106,7 @@
movew a0@,a1@+; \
movew a0@,a1@+; \
movew a0@,a1@+; \
- dbra d6,1b" : : "i" (port), "g" (buf), "g" (nr) : "a0", "a1", "d6");
+ dbra d6,1b" : : "g" (port), "g" (buf), "g" (nr) : "a0", "a1", "d6");
#define port_write(port, buf, nr) \
__asm__ __volatile__ \
@@ -123,7 +129,7 @@
movew a1@+,a0@; \
movew a1@+,a0@; \
movew a1@+,a0@; \
- dbra d6,1b" : : "i" (port), "g" (buf), "g" (nr) : "a0", "a1", "d6");
+ dbra d6,1b" : : "g" (port), "g" (buf), "g" (nr) : "a0", "a1", "d6");
void amiga_hd_setup(char *str, int *ints)
{
@@ -143,7 +149,7 @@
static int win_result(void)
{
- int i=inb_p(HD_STATUS);
+ int i=inb_p(hd_regs.hd_status);
if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
== (READY_STAT | SEEK_STAT)) {
@@ -152,7 +158,7 @@
}
printk("HD: win_result: status = 0x%02x\n",i);
if (i&1) {
- hd_error = inb(HD_ERROR);
+ hd_error = inb(hd_regs.hd_error);
printk("HD: win_result: error = 0x%02x\n",hd_error);
}
return 1;
@@ -168,7 +174,7 @@
do {
if (controller_busy() & BUSY_STAT)
return 0;
- outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
+ outb_p(0xA0 | (drive<<4) | head, hd_regs.hd_current);
if (status_ok())
return 1;
} while (--retry);
@@ -177,7 +183,7 @@
static int status_ok(void)
{
- unsigned char status = inb_p(HD_STATUS);
+ unsigned char status = inb_p(hd_regs.hd_status);
if (status & BUSY_STAT)
return 1;
@@ -196,7 +202,7 @@
unsigned char status;
do {
- status = inb_p(HD_STATUS);
+ status = inb_p(hd_regs.hd_status);
} while ((status & BUSY_STAT) && --retries);
return status;
}
@@ -214,14 +220,18 @@
return;
}
SET_INTR(intr_addr);
- outb(hd_info[drive].ctl,HD_CMD);
- outb_p(hd_info[drive].wpcom>>2,HD_PRECOMP);
- outb_p(nsect,HD_NSECTOR);
- outb_p(sect,HD_SECTOR);
- outb_p(cyl,HD_LCYL);
- outb_p(cyl>>8,HD_HCYL);
- outb_p(0xA0|(drive<<4)|head,HD_CURRENT);
- outb_p(cmd,HD_COMMAND);
+ outb(hd_info[drive].ctl,hd_regs.hd_cmd);
+
+ /* Note hd_regs.hd_error is precomp on write, but error on read */
+ outb_p(hd_info[drive].wpcom>>2,hd_regs.hd_error);
+ outb_p(nsect,hd_regs.hd_nsector);
+ outb_p(sect,hd_regs.hd_sector);
+ outb_p(cyl,hd_regs.hd_lcyl);
+ outb_p(cyl>>8,hd_regs.hd_hcyl);
+ outb_p(0xA0|(drive<<4)|head,hd_regs.hd_current);
+
+ /* Note hd_regs.hd_status is status on read and command on write */
+ outb_p(cmd,hd_regs.hd_status);
}
static int drive_busy(void)
@@ -230,7 +240,7 @@
unsigned char c;
for (i = 0; i < 500000 ; i++) {
- c = inb_p(HD_STATUS);
+ c = inb_p(hd_regs.hd_status);
c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
if (c == (READY_STAT | SEEK_STAT))
return 0;
@@ -244,12 +254,12 @@
int i;
printk(KERN_DEBUG "HD-controller reset\n");
- outb(4,HD_CMD);
+ outb(4,hd_regs.hd_cmd);
for(i = 0; i < 1000; i++) nop();
- outb(hd_info[0].ctl & 0x0f ,HD_CMD);
+ outb(hd_info[0].ctl & 0x0f ,hd_regs.hd_cmd);
if (drive_busy())
printk("HD-controller still busy\n");
- if ((hd_error = inb(HD_ERROR)) != 1)
+ if ((hd_error = inb(hd_regs.hd_error)) != 1)
printk("HD-controller reset failed: %02x\n",hd_error);
}
@@ -315,7 +325,7 @@
int retries = 100000;
while (--retries > 0)
- if (inb_p(HD_STATUS) & DRQ_STAT)
+ if (inb_p(hd_regs.hd_status) & DRQ_STAT)
return 0;
return -1;
}
@@ -329,7 +339,7 @@
int retries = 100000;
do {
- i = (unsigned) inb_p(HD_STATUS);
+ i = (unsigned) inb_p(hd_regs.hd_status);
if (i & BUSY_STAT)
continue;
if ((i & STAT_MASK) != STAT_OK)
@@ -339,14 +349,14 @@
} while (--retries > 0);
printk("HD: read_intr: status = 0x%02x\n",i);
if (i & ERR_STAT) {
- hd_error = (unsigned) inb(HD_ERROR);
+ hd_error = (unsigned) inb(hd_regs.hd_error);
printk("HD: read_intr: error = 0x%02x\n",hd_error);
}
bad_rw_intr();
do_hd_request();
return;
ok_to_read:
- port_read(HD_DATA,CURRENT->buffer,15);
+ port_read(hd_regs.hd_data,CURRENT->buffer,15);
CURRENT->errors = 0;
CURRENT->buffer += 512;
CURRENT->sector++;
@@ -363,7 +373,7 @@
SET_INTR(&read_intr);
return;
}
- (void) inb_p(HD_STATUS);
+ (void) inb_p(hd_regs.hd_status);
#if (HD_DELAY > 0)
last_req = read_timer();
#endif
@@ -377,7 +387,7 @@
int retries = 100000;
do {
- i = (unsigned) inb_p(HD_STATUS);
+ i = (unsigned) inb_p(hd_regs.hd_status);
if (i & BUSY_STAT)
continue;
if ((i & STAT_MASK) != STAT_OK)
@@ -387,7 +397,7 @@
} while (--retries > 0);
printk("HD: write_intr: status = 0x%02x\n",i);
if (i & ERR_STAT) {
- hd_error = (unsigned) inb(HD_ERROR);
+ hd_error = (unsigned) inb(hd_regs.hd_error);
printk("HD: write_intr: error = 0x%02x\n",hd_error);
}
bad_rw_intr();
@@ -402,7 +412,7 @@
end_request(1);
if (i > 0) {
SET_INTR(&write_intr);
- port_write(HD_DATA,CURRENT->buffer,15);
+ port_write(hd_regs.hd_data,CURRENT->buffer,15);
} else {
do_hd_request();
}
@@ -502,7 +512,7 @@
bad_rw_intr();
goto repeat;
}
- port_write(HD_DATA,CURRENT->buffer,15);
+ port_write(hd_regs.hd_data,CURRENT->buffer,15);
return;
}
if (CURRENT->cmd == READ) {
@@ -614,17 +624,27 @@
********************************************************/
static void hd_interrupt (struct intframe *fp, void *data)
{
+unsigned char ch;
void (*hd_irq_handler)(void) = DEVICE_INTR;
-/* Test, if this is a harddisk interrupt. MSB(0xdd2030) = 1 */
-if (inb (HD_IRQ_TEST) & 0x80)
+/* Test, if this is a harddisk interrupt. MSB = 1, hd is source of interrupt */
+if (boot_info.bi_amiga.model == AMI_4000)
+ ch = inb(HD_A4000_IRQ);
+else
+ ch = inb(HD_A1200_IRQ);
+
+if (ch & 0x80)
{
DEVICE_INTR = NULL;
timer_active &= ~(1 << HD_TIMER);
if (!hd_irq_handler)
+ {
hd_irq_handler = unexpected_hd_interrupt;
- hd_irq_handler ();
+ }
+ hd_irq_handler();
+ if (boot_info.bi_amiga.model == AMI_1200)
+ outb(0x7c | (ch & 0x03), HD_A1200_IRQ);
return;
}
@@ -646,15 +666,33 @@
printk ("Probing harddisk(s):\n");
NR_HD = 0;
-/* Test, if it's an A4000 or an A1200 */
-if ((boot_info.bi_amiga.model != AMI_4000) && (boot_info.bi_amiga.model != AMI_1200))
- {
+/* Test if an A4000 or an A1200 and setup the base of hd_regs acordingly */
+if (boot_info.bi_amiga.model == AMI_4000)
+{
+ hd_regs.hd_data = (unsigned char *)HD_BASE_A4000;
+}
+else if (boot_info.bi_amiga.model == AMI_1200)
+{
+ hd_regs.hd_data = (unsigned char *)HD_BASE_A1200;
+}
+else /* Not A4000 nor A1200, doesn't have a supported IDE controller */
+{
printk ("IDE harddisk controller not present.\n");
hd_gendisk.nr_real = NR_HD;
return;
- }
+}
-outb (IDE_DISABLE_IRQ, HD_CMD); /* Disable HD-interrupt */
+/* Now set the rest of hd_regs struct */
+hd_regs.hd_error = hd_regs.hd_data + HD_ERROR;
+hd_regs.hd_nsector = hd_regs.hd_data + HD_NSECTOR;
+hd_regs.hd_sector = hd_regs.hd_data + HD_SECTOR;
+hd_regs.hd_lcyl = hd_regs.hd_data + HD_LCYL;
+hd_regs.hd_hcyl = hd_regs.hd_data + HD_HCYL;
+hd_regs.hd_current = hd_regs.hd_data + HD_CURRENT;
+hd_regs.hd_status = hd_regs.hd_data + HD_STATUS;
+hd_regs.hd_cmd = hd_regs.hd_data + HD_CMD;
+
+outb (IDE_DISABLE_IRQ, hd_regs.hd_cmd); /* Disable HD-interrupt */
cli (); /* Disable interrupts */
for (drive=0; drive<2; drive++)
@@ -667,20 +705,21 @@
}
/* select drive */
- outb_p ((unsigned char) (0xA0 | (drive<<4)), HD_CURRENT);
+ outb_p ((unsigned char) (0xA0 | (drive<<4)), hd_regs.hd_current);
/* Set identify command */
- outb_p (WIN_IDENTIFY, HD_COMMAND);
+ /* Note hd_regs.hd_status is status on read and command on write */
+ outb_p (WIN_IDENTIFY, hd_regs.hd_status);
drive_found = 0;
/* Test, if ready to read */
for (i=0; i<HD_ID_RETRIES; i++)
{
- if ((inb_p(HD_STATUS) & (DRQ_STAT|READY_STAT)) == (DRQ_STAT|READY_STAT)) /* ++hn: Detect Seagate drives properly */
+ if ((inb_p(hd_regs.hd_status) & (DRQ_STAT|READY_STAT)) == (DRQ_STAT|READY_STAT)) /* ++hn: Detect Seagate drives properly */
{
drive_found = 1;
#ifdef DEBUG
- printk("hd%d: WIN_IDENTIFY: status = 0x%hx\n", drive, inb_p(HD_STATUS));
+ printk("hd%d: WIN_IDENTIFY: status = 0x%hx\n", drive, inb_p(hd_regs.hd_status));
#endif
break;
}
@@ -688,7 +727,7 @@
if (drive_found)
{
- port_read (HD_DATA, Identify, 15);
+ port_read (hd_regs.hd_data, Identify, 15);
for (i=0; i<256; i++)
/* We need to swap MSB and LSB */
Identify [i] = (Identify [i] << 8) | (Identify [i] >> 8);
@@ -711,6 +750,7 @@
printk ("hd%c not found.\n", (char)drive+'a'); /* ++hn: use hda/hdb naming for the user-messages */
}
sti (); /* Enable interrupts */
+
/* Add the interrupt handler */
if (NR_HD)
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/block/ataflop.c linux-0.9pl4/drivers/block/ataflop.c
--- linux-0.9pl3/drivers/block/ataflop.c Sun Aug 14 10:30:45 1994
+++ linux-0.9pl4/drivers/block/ataflop.c Thu Nov 24 21:13:32 1994
@@ -2,8 +2,40 @@
* linux/kernel/blk_drv/floppy.c
*
* Copyright (C) 1993 Greg Harp
- * Atari Support by Björn Brauel
+ * Atari Support by Bjoern Brauel, Roman Hodek
*
+ * Big cleanup Sep 11..14 1994 Roman Hodek:
+ * - Driver now works interrupt driven
+ * - Support for two drives; should work, but I cannot test that :-(
+ * - Reading is done in whole tracks and buffered to speed up things
+ * - Disk change detection and drive deselecting after motor-off
+ * similar to TOS
+ * - Autodetection of disk format (DD/HD); untested yet, because I
+ * don't have an HD drive :-(
+ *
+ * Fixes Nov 13 1994 Martin Schaller:
+ * - Autodetection works now
+ * - Support for 5 1/4" disks
+ * - Removed drive type (unknown on atari)
+ * - Do seeks with 8 Mhz
+ *
+ * Things left to do:
+ * - Formatting
+ * - Maybe a better strategy for disk change detection (does anyone
+ * know one?)
+ * - In case of disk errors, don't give up immediatly but retry
+ * several times
+ * - There are some strange problems left: The strangest one is
+ * that, at least on my TT (4+4MB), the first 2 Bytes of the last
+ * page of the TT-Ram (!) change their contents (some bits get
+ * set) while a floppy DMA is going on. But there are no accesses
+ * to these memory locations from the kernel... (I tested that by
+ * making the page read-only). I cannot explain what's going on...
+ * - Sometimes the drive-change-detection stops to work. The
+ * function is still called, but the WP bit always reads as 0...
+ * Maybe a problem with the status reg mode or a timing problem.
+ * Note 10/12/94: The change detection now seems to work reliably.
+ * There is no proof, but I've seen no hang for a long time...
*/
#include <linux/config.h>
@@ -20,351 +52,950 @@
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <asm/system.h>
+#include <asm/bitops.h>
#include <linux/atarihw.h>
#include <linux/atariints.h>
+#include <linux/atari_stdma.h>
#define MAJOR_NR FLOPPY_MAJOR
#include "blk.h"
-#undef __notneeded__
-/*
- * Defines
+/* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with
+ * little additional rework in this file). But I'm not yet sure if
+ * some other code depends on the number of floppies... (It is defined
+ * in a public header!)
*/
-#define MAX_SECTORS 22
-#define RAW_BUF 900000
+#if 0
+#undef FD_MAX_UNITS
+#define FD_MAX_UNITS 2
+#endif
-/*
- * Error codes
- */
-#define FD_OK 0 /* operation succeeded */
-#define FD_ERROR -1 /* general error (seek, read, write, etc) */
-#define FD_NOUNIT 1 /* unit does not exist */
-#define FD_UNITBUSY 2 /* unit already active */
-#define FD_NOTACTIVE 3 /* unit is not active */
-#define FD_NOTREADY 4 /* unit is not ready (motor not on/no disk) */
+#define TRACKBUFFER 1
+#undef DEBUG
-/*
- * Floppy ID values
- */
-#define FD_NODRIVE 0x00000000 /* response when no unit is present */
-#define FD_HD_3 0xaaaaaaaa /* high-density 3.5'' (1760K) drive */
-#define FD_DD_3 0xbbbbbbbb /* high-density 3.5'' (880K) drive */
+/* Disk types: DD or HD */
+static struct atari_disk_type {
+ const char *name;
+ unsigned spt; /* sectors per track */
+ unsigned blocks; /* total number of blocks */
+ unsigned fdc_speed; /* fdc_speed setting */
+ unsigned stretch; /* track doubling ? */
+} disk_type[] = {
+ { "d360", 9, 720, 0, 0}, /* 360kB diskette */
+ { "h1220",15,2400, 3, 0}, /* 1.2MB diskette */
+ { "D360", 9, 720, 0, 1}, /* 360kb in 720kb drive */
+ { "D720", 9,1440, 0, 0}, /* 720kb diskette (DD) */
+/* the following 2 are only aliases on the atari, since we can't read/write
+ with 300kbps */
+ { "h360", 9, 720, 0, 1}, /* 360kb in 1.2MB drive */
+ { "h720", 9,1440, 0, 0}, /* 720kb in 1.2MB drive */
+ { "H1440",18,2880, 3, 0} /* 1.44MB diskette (HD) */
+};
+#define NUM_DISK_TYPES (sizeof(disk_type)/sizeof(*disk_type))
-/* Atari: Auto probing not implemented yet! If CONFIG_FLOPPY_DD_ONLY
- * is not defined, all accesses are done for a HD disk.
+/* current info on each unit */
+static struct atari_floppy_struct {
+ int connected; /* !=0 : drive is connected */
+ int autoprobe; /* !=0 : do autoprobe */
+
+ struct atari_disk_type *disktype; /* current type of disk */
+
+ int track; /* current head position or -1
+ * if unknown */
+ unsigned int steprate; /* steprate setting */
+ unsigned int wpstat; /* current state of WP signal
+ * (for disk change detection) */
+} unit[FD_MAX_UNITS];
+
+
+#define FDC_READ(reg) ({ \
+ /* unsigned long __flags; */ \
+ unsigned short __val; \
+ /* save_flags(__flags); cli(); */ \
+ dma_wd.dma_mode_status = 0x80 | (reg); \
+ udelay(40); \
+ __val = dma_wd.fdc_acces_seccount; \
+ /* restore_flags(__flags); */ \
+ __val & 0xff; \
+})
+
+#define FDC_WRITE(reg,val) \
+ do { \
+ /* unsigned long __flags; */ \
+ /* save_flags(__flags); cli(); */ \
+ dma_wd.dma_mode_status = 0x80 | (reg); \
+ udelay(40); \
+ dma_wd.fdc_acces_seccount = (val); \
+ /* restore_flags(__flags); */ \
+ } while(0)
+
+
+/* Buffering variables:
+ * First, there is a DMA buffer in ST-RAM that is used for floppy DMA
+ * operations. Second, a track buffer is used to cache a whole track
+ * of the disk to save read operations. These are two seperate buffers
+ * because that allows write operations without clearing the track buffer.
*/
-/* For Atari, fields rdsz, wrsz, sm, pc1, pc2, sd, st, st unused */
+#define MAX_SECTORS 22
-static struct fd_drive_type drive_types[] = {
-/* code name tr he rdsz wrsz sm pc1 pc2 sd st st*/
- { FD_HD_3, "HD 3.5", 160, 2, 25000, 25000, 2, 80,161, 3000, 18000, 1000},
- { FD_DD_3, "DD 3.5", 160, 2, 25000, 25000, 1, 80,161, 3000, 18000, 1000},
- { FD_NODRIVE, "No Drive", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
-};
-#ifdef __notneeded__
-static int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]);
-#endif
+unsigned char *DMABuffer; /* buffer for writes */
+static unsigned long PhysDMABuffer; /* physical address */
-static struct fd_data_type data_types[] = {
- { "Atari", 9 }
-};
-#ifdef __notneeded__
-static int num_da_types = sizeof(data_types) / sizeof(data_types[0]);
+#ifdef TRACKBUFFER
+unsigned char *TrackBuffer; /* buffer for reads */
+static unsigned long PhysTrackBuffer; /* physical address */
+static int BufferDrive, BufferSide, BufferTrack;
+static int error_drive, error_side, error_track;
+
+#define SECTOR_BUFFER(sec) (TrackBuffer + ((sec)-1)*512)
+#define IS_BUFFERED(drive,side,track) \
+ (BufferDrive == (drive) && BufferSide == (side) && BufferTrack == (track))
#endif
-
-/* current info on each unit */
-static struct floppy_struct unit[FD_MAX_UNITS];
-
-/* track buffer */
-static int savedtrack = -1;
-unsigned char *trackdata; /* allocated by atari_stram_alloc */
-
/*
* These are global variables, as that's the easiest way to give
* information to interrupts. They are the data used for the current
* request.
*/
-static char block_flag = 0;
-static int selected = 0;
-static struct wait_queue *wait_on_floppy_select = NULL;
-static struct wait_queue *wait_fd_block = NULL;
+static int SelectedDrive = 0;
+static int ReqCmd, ReqBlock;
+static int ReqSide, ReqTrack, ReqSector, ReqCnt;
+static int HeadSettleFlag = 0;
+static unsigned char *ReqData, *ReqBuffer;
+static int MotorOn = 0, MotorOffTrys;
/* Synchronization of FDC access. */
-#ifdef __notneeded__
static volatile int fdc_busy = 0;
static struct wait_queue *fdc_wait = NULL;
-static struct wait_queue *motor_wait = NULL;
+
+static unsigned int changed_floppies = 0xff, fake_change = 0;
+#define CHECK_CHANGE_DELAY HZ/2
+
+#define FD_MOTOR_OFF_DELAY (3*HZ)
+#define FD_MOTOR_OFF_MAXTRY (10*20)
+
+#define START_MOTOR_OFF_TIMER(delay) \
+ do { \
+ motor_off_timer.expires = (delay); \
+ add_timer( &motor_off_timer ); \
+ MotorOffTrys = 0; \
+ } while(0)
+
+#define START_CHECK_CHANGE_TIMER(delay) \
+ do { \
+ timer_table[FLOPPY_TIMER].expires = jiffies + (delay); \
+ timer_active |= (1 << FLOPPY_TIMER); \
+ } while(0)
+
+
+/*
+ * The driver is trying to determine the correct media format
+ * while Probing is set. fd_rwsec_done() clears it after a
+ * successful access.
+ */
+static int Probing = 0;
+
+/* This flag is set when a dummy seek is necesary to make the WP
+ * status bit accessible.
+ */
+static int NeedSeek = 0;
+
+
+#ifdef DEBUG
+#define DPRINT(a) printk a
+#else
+#define DPRINT(a)
#endif
#if 0
-static unsigned int changed_floppies = 0;
+
+unsigned long RCont = 0;
+
+#define TEST_PAGE(str,adr) \
+ do { \
+ if (*(unsigned long *)0xc03ff000 != RCont) { \
+ printk("*0xc03ff000 = %08lx mem_map[]=%d\n", \
+ (RCont = *(unsigned long *)0xc03ff000), \
+ mem_map[MAP_NR(0xc03ff000)] ); \
+ printk("%s ",(str)); \
+ printk("%08lx\n",(unsigned long)(adr)); \
+ } \
+ } while(0)
+
+#else
+
+#define TEST_PAGE(str,adr) do {} while(0)
+
#endif
-/*======================================================================
- Select the side to use for a particular drive.
- The drive must have been calibrated at some point before this.
- The drive must also be active and the motor must be running.
-======================================================================*/
-#ifdef __notneeded__
-static void fd_select_side(int drive, int side)
-{
- unsigned long flags;
+/***************************** Prototypes *****************************/
+
+static void fd_select_side( int side );
+static void fd_select_drive( int drive );
+static void fd_deselect( void );
+static void fd_motor_off_timer( unsigned long dummy );
+static void check_change( void );
+static __inline__ void set_head_settle_flag( void );
+static __inline__ int get_head_settle_flag( void );
+static void floppy_irq( struct intframe *fp, void *data );
+static void do_fd_action( int drive );
+static void fd_calibrate( void );
+static void fd_calibrate_done( int status );
+static void fd_seek( void );
+static void fd_seek_done( int status );
+static void fd_rwsec( void );
+#ifdef TRACKBUFFER
+static void fd_readtrack_check( unsigned long dummy );
+#endif
+static void fd_rwsec_done( int status );
+static void finish_fdc( void );
+static void floppy_off( unsigned int nr);
+static __inline__ void copy_buffer( void *from, void *to);
+static void setup_req_params( int drive );
+static void redo_fd_request( void);
+static int fd_ioctl( struct inode *inode, struct file *filp, unsigned int
+ cmd, unsigned long param);
+static void fd_probe( int drive );
+static int fd_test_drive_present( int drive );
+static void config_types( void );
+static int floppy_open( struct inode *inode, struct file *filp );
+static void floppy_release( struct inode * inode, struct file * filp );
+
+/************************* End of Prototypes **************************/
+
+static struct timer_list motor_off_timer =
+ { NULL, NULL, 0, 0, fd_motor_off_timer };
+#ifdef TRACKBUFFER
+static struct timer_list readtrack_timer =
+ { NULL, NULL, 0, 0, fd_readtrack_check };
+#endif
+
+
+
+
+/* Select the side to use. */
+
+static void fd_select_side( int side )
+
+{ unsigned long flags;
save_flags(flags);
cli();
- if(side==0)
- {
- sound_ym.rd_data_reg_sel=14; /* Select PSG Port A */
- sound_ym.wd_data = sound_ym.rd_data_reg_sel | 0x01;
- }
- else
- {
- sound_ym.rd_data_reg_sel=14; /* Select PSG Port A */
- sound_ym.wd_data = sound_ym.rd_data_reg_sel & 0xfe;
- }
+ sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */
+ sound_ym.wd_data = (side == 0) ? sound_ym.rd_data_reg_sel | 0|01 :
+ sound_ym.rd_data_reg_sel & 0xfe;
restore_flags(flags);
}
-#endif
-#ifdef __notneeded__
-static struct timer_list motor_on_timer;
-static struct timer_list motor_off_timer[FD_MAX_UNITS];
-static int on_attempts;
-#endif
+/* Select a drive, update the FDC's track register and set the correct
+ * clock speed for this disk's type.
+ */
+
+static void fd_select_drive( int drive )
-static void fd_select (int drive, int side)
{
unsigned long flags;
unsigned char tmp;
- if (drive == selected)
+ if (drive == SelectedDrive)
return;
- selected = drive;
save_flags(flags);
cli();
-
- if (side == 0)
- {
- sound_ym.rd_data_reg_sel=14; /* Select PSG Port A */
+ sound_ym.rd_data_reg_sel = 14; /* Select PSG Port A */
tmp = sound_ym.rd_data_reg_sel;
- sound_ym.wd_data = (tmp & ~2) | 1; /* Select Side 0 and Drive A */
- }
- else
- {
+ sound_ym.wd_data = (tmp | DSKDRVNONE) & ~(drive == 0 ? DSKDRV0 : DSKDRV1);
+ restore_flags(flags);
+
+ /* restore track register to saved value */
+ FDC_WRITE( FDCREG_TRACK, unit[drive].track );
+ udelay(40);
+
+ /* select 8/16 MHz */
+ if (unit[drive].disktype)
+ dma_wd.fdc_speed = unit[drive].disktype->fdc_speed;
+
+ SelectedDrive = drive;
+}
+
+
+/* Deselect both drives. */
+
+static void fd_deselect( void )
+
+{ unsigned long flags;
+
+ save_flags(flags);
+ cli();
sound_ym.rd_data_reg_sel=14; /* Select PSG Port A */
- tmp = sound_ym.rd_data_reg_sel;
- sound_ym.wd_data = tmp & ~3; /* Select Side 1 and Drive A */
+ sound_ym.wd_data = sound_ym.rd_data_reg_sel | 7; /* no drives selected */
+ restore_flags(flags);
+
+ SelectedDrive = -1;
+}
+
+
+/* This timer function deselects the drives when the FDC switched the
+ * motor off. The deselection cannot happen earlier because the FDC
+ * counts the index signals, which arrive only if one drive is selected.
+ */
+
+static void fd_motor_off_timer( unsigned long dummy )
+
+{ unsigned long flags;
+ unsigned char status;
+ int delay;
+
+ del_timer( &motor_off_timer );
+
+ if (SelectedDrive < 0)
+ /* no drive selected, needn't deselect anyone */
+ return;
+
+ save_flags(flags);
+ cli();
+
+ if (stdma_islocked())
+ goto retry;
+
+ status = FDC_READ( FDCREG_STATUS );
+
+ if (!(status & 0x80)) {
+ /* motor already turned off by FDC -> deselect drives */
+ fd_deselect();
+ restore_flags(flags);
+ MotorOn = 0;
+ return;
}
+ /* not yet off, try again */
+ retry:
restore_flags(flags);
+ /* Test again later; if tested too often, it seems there is no disk
+ * in the drive and the FDC will leave the motor on forever (or,
+ * at least until a disk is inserted). So we'll test only twice
+ * per second from then on...
+ */
+ delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ?
+ (++MotorOffTrys, HZ/20) : HZ/2;
+ START_MOTOR_OFF_TIMER( delay );
}
-static void fd_deselect (int drive)
-{
+
+/* This function is repeatedly called to detect disk changes (as good
+ * as possible) and keep track of the current state of the write protection.
+ */
+
+static void check_change( void )
+
+{ static int drive = 0;
+
unsigned long flags;
+ unsigned char old_porta;
+ int stat;
- if (drive != selected)
- return;
+ if (++drive > 1 || !unit[drive].connected)
+ drive = 0;
+
+ if (!stdma_islocked()) {
save_flags(flags);
cli();
- sound_ym.rd_data_reg_sel=14; /* Select PSG Port A */
- sound_ym.wd_data = sound_ym.rd_data_reg_sel | 7; /* no drives selected */
+ TEST_PAGE("check change timer",0);
+ sound_ym.rd_data_reg_sel = 14;
+ old_porta = sound_ym.rd_data_reg_sel;
+ sound_ym.wd_data = (old_porta | DSKDRVNONE) &
+ ~(drive == 0 ? DSKDRV0 : DSKDRV1);
+ stat = !!(FDC_READ( FDCREG_STATUS ) & FDCSTAT_WPROT);
+ sound_ym.wd_data = old_porta;
restore_flags(flags);
- selected=-1;
+ if (stat != unit[drive].wpstat) {
+ DPRINT(( "wpstat[%d] = %d\n", drive, stat ));
+ unit[drive].wpstat = stat;
+ set_bit (drive, &changed_floppies);
+ }
+ }
+
+ START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
}
-static void fd_nobusy(void)
-{
- unsigned char fd_status;
- do
- fd_status = mfp.par_dt_reg & 0x20;
- while(fd_status != 0);
+/* Handling of the Head Settling Flag: This flag should be set after each
+ * seek operation, because we dont't use seeks with verify.
+ */
+static __inline__ void set_head_settle_flag( void )
+
+{
+ HeadSettleFlag = FDCCMDADD_E;
}
-/*======================================================================
- Seek the drive to track 0.
- The drive must be active and the motor must be running.
- Returns standard floppy error code.
-======================================================================*/
-#ifdef __notneeded__
-static int fd_calibrate(int drive)
+static __inline__ int get_head_settle_flag( void )
+
{
+ int tmp = HeadSettleFlag;
+ HeadSettleFlag = 0;
+ return( tmp );
+}
- fd_select(drive,0);
- dma_wd.dma_mode_status=FDCSELREG_STP;
- dma_wd.fdc_acces_seccount=FDCCMD_RESTORE | FDCCMDADD_V ;
- fd_nobusy();
- fd_deselect(drive);
- return 1;
+
+/* General Interrupt Handling */
+
+static void (*FloppyIRQHandler)( int status ) = NULL;
+
+static void floppy_irq( struct intframe *fp, void *data )
+
+{
+ unsigned char status;
+ void (*handler)( int );
+
+ handler = FloppyIRQHandler;
+ FloppyIRQHandler = NULL;
+
+ if (handler) {
+ nop();
+ status = FDC_READ( FDCREG_STATUS );
+ DPRINT(("FDC irq, status = %02x handler = %08lx\n",status,(unsigned long)handler));
+ udelay(40);
+ handler( status );
+ }
+ else {
+ DPRINT(("FDC irq, no handler\n"));
+ }
}
+
+#define SET_IRQ_HANDLER(proc) do { FloppyIRQHandler = (proc); } while(0)
+
+
+/* do_fd_action() is the general procedure for a fd request: All
+ * required parameter settings (drive select, side select, track
+ * position) are checked and set if needed. For each of these
+ * parameters and the actual reading or writing exist two functions:
+ * one that starts the setting (or skips it if possible) and one
+ * callback for the "done" interrupt. Each done func calls the next
+ * set function to propagate the request down to fd_rwsec_done().
+ */
+
+static void do_fd_action( int drive )
+
+{
+ TEST_PAGE("do_fd_action",drive);
+ DPRINT(("do_fd_action\n"));
+
+#ifdef TRACKBUFFER
+ repeat:
+
+ if (IS_BUFFERED( drive, ReqSide, ReqTrack )) {
+ if (ReqCmd == READ) {
+ copy_buffer( SECTOR_BUFFER(ReqSector), ReqData );
+ if (++ReqCnt < 2) {
+ /* read next sector */
+ setup_req_params( drive );
+ goto repeat;
+ }
+ else {
+ /* all sectors finished */
+ end_request( 1 );
+ redo_fd_request();
+ return;
+ }
+ }
+ else {
+ /* cmd == WRITE, pay attention to track buffer
+ * consistency! */
+ copy_buffer( ReqData, SECTOR_BUFFER(ReqSector) );
+ }
+ }
#endif
-/*======================================================================
- Seek the drive to the requested cylinder.
- The drive must have been calibrated at some point before this.
- The drive must also be active and the motor must be running.
-======================================================================*/
-static int fd_seek(unsigned short drive, unsigned short track)
-{
- dma_wd.dma_mode_status=FDCSELREG_DTA;
- nop();
- dma_wd.fdc_acces_seccount=track;
- udelay (1);
- dma_wd.dma_mode_status=FDCSELREG_STP;
- nop();
- dma_wd.fdc_acces_seccount=FDCCMD_SEEK | FDCCMDADD_V ;
- udelay (1);
- fd_nobusy();
+ if (SelectedDrive != drive)
+ fd_select_drive( drive );
- return 1;
+ if (unit[drive].track == -1)
+ fd_calibrate();
+ else if (unit[drive].track != ReqTrack << unit[drive].disktype->stretch)
+ fd_seek();
+ else
+ fd_rwsec();
}
-struct header {
- unsigned char magic;
- unsigned char track;
- unsigned char sect;
- unsigned char ord;
- unsigned char labels[16];
- unsigned long hdrchk;
- unsigned long datachk;
-};
+/* Seek to track 0 if the current track is unknown */
+
+static void fd_calibrate( void )
+
+{
+ TEST_PAGE("fd_calibrate",0);
+ if (unit[SelectedDrive].track >= 0) {
+ fd_calibrate_done( 0 );
+ return;
+ }
+
+ dma_wd.fdc_speed = 0; /* always seek with 8 Mhz */;
+ DPRINT(("fd_calibrate\n"));
+ SET_IRQ_HANDLER( fd_calibrate_done );
+ /* we can't verify, since the speed may be incorrect */
+ FDC_WRITE( FDCREG_CMD, FDCCMD_RESTORE | unit[SelectedDrive].steprate );
+
+ NeedSeek = 1;
+ MotorOn = 1;
+ /* wait for IRQ */
+}
+static void fd_calibrate_done( int status )
-/*==========================================================================
- atari_write converts track/labels data to raw track data
-==========================================================================*/
-static void atari_write(int dr, unsigned short tr, unsigned short sec)
{
- unsigned long phys_secbuf,flags;
+ TEST_PAGE("calibrate_done",0);
+ DPRINT(("fd_calibrate_done()\n"));
- sec=sec+1;
+ /* set the correct speed now */
+ dma_wd.fdc_speed = unit[SelectedDrive].disktype->fdc_speed;
+ if (status & FDCSTAT_RECNF) {
+ printk( "fd%d: restore failed\n", SelectedDrive );
+ end_request( 0 );
+ redo_fd_request();
+ }
+ else {
+ unit[SelectedDrive].track = 0;
+ fd_seek();
+ }
+}
- phys_secbuf = (unsigned long) trackdata;
- save_flags(flags);
- cli();
+/* Seek the drive to the requested track. The drive must have been
+ * calibrated at some point before this.
+ */
- fd_select (dr, tr & 1);
+static void fd_seek( void )
- tr=tr/2;
+{
+ TEST_PAGE("fd_seek",0);
+ if (unit[SelectedDrive].track == ReqTrack <<
+ unit[SelectedDrive].disktype->stretch) {
+ fd_seek_done( 0 );
+ return;
+ }
- /* Setup head pos. */
- fd_seek(dr,tr);
+ dma_wd.fdc_speed = 0; /* always seek witch 8 Mhz */
+ DPRINT(("fd_seek() to track %d\n",ReqTrack));
+ FDC_WRITE( FDCREG_DATA, ReqTrack <<
+ unit[SelectedDrive].disktype->stretch);
+ udelay(40);
+ SET_IRQ_HANDLER( fd_seek_done );
+ FDC_WRITE( FDCREG_CMD, FDCCMD_SEEK | unit[SelectedDrive].steprate );
+
+ MotorOn = 1;
+ set_head_settle_flag();
+ /* wait for IRQ */
+}
- /* Setup DMA */
- dma_wd.dma_lo=(unsigned char)phys_secbuf;
- phys_secbuf = phys_secbuf >> 8;
- dma_wd.dma_md=(unsigned char)phys_secbuf;
- phys_secbuf = phys_secbuf >> 8;
- dma_wd.dma_hi=(unsigned char)phys_secbuf;
+static void fd_seek_done( int status )
- /* Clear FIFO and switch DMA to read-mode ! */
- dma_wd.dma_mode_status=0x190;
- dma_wd.dma_mode_status=0x90;
- dma_wd.dma_mode_status=0x190;
+{
+ TEST_PAGE("fd_seek_done",0);
+ DPRINT(("fd_seek_done()\n"));
+ /* set the correct speed */
+ dma_wd.fdc_speed = unit[SelectedDrive].disktype->fdc_speed;
+ if (status & FDCSTAT_RECNF) {
+ printk( "fd%d: seek error\n", SelectedDrive );
+ /* we don't know exactly which track we are on now! */
+ unit[SelectedDrive].track = -1;
+ end_request( 0 );
+ redo_fd_request();
+ }
+ else {
+ unit[SelectedDrive].track = ReqTrack <<
+ unit[SelectedDrive].disktype->stretch;
+ NeedSeek = 0;
+ fd_rwsec();
+ }
+}
- /* Transmit only 1 Sector */
- dma_wd.fdc_acces_seccount=0x01;
- udelay (1);
+/* This does the actual reading/writing after positioning the head
+ * over the correct track.
+ */
+
+#ifdef TRACKBUFFER
+static int MultReadInProgress = 0;
+#endif
- dma_wd.dma_mode_status=FDCSELREG_SEC | 0x100 ;
+
+static void fd_rwsec( void )
+
+{
+ unsigned long paddr, flags;
+ unsigned int rwflag, old_motoron;
+ unsigned int track;
+#ifdef TRACKBUFFER
+ int single_read = 0;
+#endif
+
+ TEST_PAGE("fd_rwsec",0);
+ DPRINT(("fd_rwsec(), Sec=%d, Access=%c\n",ReqSector, ReqCmd == WRITE ? 'w' : 'r' ));
+ if (ReqCmd == WRITE) {
+ copy_buffer( ReqData, DMABuffer );
+ cache_push( PhysDMABuffer, 512 );
+ paddr = PhysDMABuffer;
+ rwflag = 0x100;
+ }
+ else {
+#ifdef TRACKBUFFER
+ paddr = PhysTrackBuffer;
+ if (error_drive == SelectedDrive && error_track == ReqTrack
+ && error_side == ReqSide)
+ {
+ DPRINT (("fd_rwsec: single sector read after error\n"));
+ single_read = 1;
+ paddr = PhysDMABuffer;
+ }
+#else
+ paddr = PhysDMABuffer;
+#endif
+ rwflag = 0;
+ }
+
+ fd_select_side( ReqSide );
+
+ /* Start sector of this operation */
+#ifdef TRACKBUFFER
+ FDC_WRITE( FDCREG_SECTOR, rwflag || single_read ? ReqSector : 1 );
+#else
+ FDC_WRITE( FDCREG_SECTOR, ReqSector );
+#endif
+ /* Cheat for track if stretch != 0 */
+ if (unit[SelectedDrive].disktype->stretch) {
+ track = FDC_READ( FDCREG_TRACK);
+ FDC_WRITE( FDCREG_TRACK, track >>
+ unit[SelectedDrive].disktype->stretch);
+ }
+ udelay(40);
+
+ /* Setup DMA */
+ TEST_PAGE("before setting DMA",paddr);
+ save_flags(flags);
+ cli();
+ dma_wd.dma_lo = (unsigned char)paddr;
+ paddr >>= 8;
+ nop();
+ dma_wd.dma_md = (unsigned char)paddr;
+ paddr >>= 8;
nop();
- dma_wd.fdc_acces_seccount=sec;
- udelay (1);
+ dma_wd.dma_hi = (unsigned char)paddr;
+ nop();
+ restore_flags(flags);
+ TEST_PAGE("after setting DMA",ReqTrack*2+ReqSide);
- /* Start Write */
- dma_wd.dma_mode_status=FDCSELREG_STP | 0x100 ;
+ /* Clear FIFO and switch DMA to correct mode */
+ dma_wd.dma_mode_status = 0x90 | rwflag;
+ nop();
+ dma_wd.dma_mode_status = 0x90 | (rwflag ^ 0x100);
+ nop();
+ dma_wd.dma_mode_status = 0x90 | rwflag;
nop();
- dma_wd.fdc_acces_seccount=FDCCMD_WRSEC ;
- udelay (1);
- fd_nobusy(); /* Wait for IRQ 5 */
+ /* How many sectors for DMA */
+#ifdef TRACKBUFFER
+ dma_wd.fdc_acces_seccount =
+ rwflag || single_read ? 1 : unit[SelectedDrive].disktype->spt;
+#else
+ dma_wd.fdc_acces_seccount = 1;
+#endif
- restore_flags(flags);
+ udelay(40);
- fd_deselect(dr);
+ /* Start operation */
+ dma_wd.dma_mode_status = FDCSELREG_STP | rwflag;
+ udelay(40);
+ SET_IRQ_HANDLER( fd_rwsec_done );
+ dma_wd.fdc_acces_seccount =
+ (rwflag ? (FDCCMD_WRSEC | FDCCMDADD_P) :
+#ifdef TRACKBUFFER
+ (FDCCMD_RDSEC | (single_read ? 0 : FDCCMDADD_M))
+#else
+ FDCCMD_RDSEC
+#endif
+ ) | get_head_settle_flag();
- udelay (10);
+ old_motoron = MotorOn;
+ MotorOn = 1;
+ NeedSeek = 1;
+ /* wait for interrupt */
+
+#ifdef TRACKBUFFER
+ if (!rwflag && !single_read) {
+ /* If reading a whole track, wait about one disk rotation and
+ * then check if all sectors are read. The FDC will even
+ * search for the first non-existant sector and need 1 sec to
+ * recognise that it isn't present :-(
+ */
+ readtrack_timer.expires = HZ/5 + 3*HZ/50 + (old_motoron ? 0 : HZ);
+ /* 1 rot. + 5 rot.s if motor was off */
+ add_timer( &readtrack_timer );
+ MultReadInProgress = 1;
}
+#endif
+ TEST_PAGE("leaving rwsec",0);
+}
-/*==========================================================================
- atari_read reads a raw track of data into a track buffer
-==========================================================================*/
-static int atari_read(int dr, unsigned short tr, unsigned short sec)
-{
- unsigned long phys_secbuf,flags;
- phys_secbuf = (unsigned long) trackdata;
+#ifdef TRACKBUFFER
- sec=sec+1;
+static void fd_readtrack_check( unsigned long dummy )
+
+{ unsigned long flags, addr;
save_flags(flags);
cli();
- fd_select (dr, tr & 1);
+ TEST_PAGE("check timer",0);
+ del_timer( &readtrack_timer );
- tr=tr/2;
+ if (!MultReadInProgress) {
+ /* This prevents a race condition that could arise if the
+ * interrupt is triggered while the calling of this timer
+ * callback function takes place. The IRQ function then has
+ * already cleared 'MultReadInProgress' when control flow
+ * gets here.
+ */
+ restore_flags(flags);
+ return;
+ }
- /* Setup head pos. */
- fd_seek(dr,tr);
+ /* get the current DMA address */
+ addr = dma_wd.dma_lo & 0xff;
+ nop();
+ addr |= (dma_wd.dma_md & 0xff) << 8;
+ nop();
+ addr |= (dma_wd.dma_hi & 0xff) << 16;
+ nop();
+ if (addr >= PhysTrackBuffer + unit[SelectedDrive].disktype->spt*512) {
+ /* already read enough data, force an FDC interrupt to stop
+ * the read operation
+ */
+ SET_IRQ_HANDLER( NULL );
+ restore_flags(flags);
+ DPRINT(("fd_readtrack_check(): done\n"));
+ FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );
+ TEST_PAGE("Int force",0);
+ udelay(40);
- /* Setup DMA */
- dma_wd.dma_lo=(unsigned char)phys_secbuf;
- phys_secbuf = phys_secbuf >> 8;
- dma_wd.dma_md=(unsigned char)phys_secbuf;
- phys_secbuf = phys_secbuf >> 8;
- dma_wd.dma_hi=(unsigned char)phys_secbuf;
+ /* No error until now -- the FDC would have interrupted
+ * otherwise!
+ */
+ fd_rwsec_done( 0 );
+ }
+ else {
+ /* not yet finished, wait another tenth rotation */
+ restore_flags(flags);
+ DPRINT(("fd_readtrack_check(): not yet finished\n"));
+ readtrack_timer.expires = HZ/5/10;
+ add_timer( &readtrack_timer );
+ }
+}
+#endif
- /* Clear FIFO and switch DMA to read-mode ! */
- dma_wd.dma_mode_status=0x90;
- dma_wd.dma_mode_status=0x190;
- dma_wd.dma_mode_status=0x90;
- /* Transmit only 1 Sector */
- dma_wd.fdc_acces_seccount=0x01;
- udelay (1);
+static void fd_rwsec_done( int status )
- dma_wd.dma_mode_status=FDCSELREG_SEC;
- nop();
- dma_wd.fdc_acces_seccount=sec;
- udelay (1);
+{
+ unsigned int track;
+#ifdef TRACKBUFFER
+ int single_read = MultReadInProgress == -1;
+#endif
+
+ TEST_PAGE("rwsec_done",ReqTrack*2+ReqSide);
+ DPRINT(("fd_rwsec_done()\n"));
+
+#ifdef TRACKBUFFER
+ if (ReqCmd == READ && !MultReadInProgress) return;
+ MultReadInProgress = 0;
- /* Start READ */
- dma_wd.dma_mode_status=FDCSELREG_STP;
+ if (ReqCmd == READ && !single_read)
+ del_timer( &readtrack_timer );
+#endif
+
+ /* Correct the track if stretch != 0 */
+ if (unit[SelectedDrive].disktype->stretch) {
+ track = FDC_READ( FDCREG_TRACK);
+ FDC_WRITE( FDCREG_TRACK, track <<
+ unit[SelectedDrive].disktype->stretch);
+ }
+
+#ifndef TRACKBUFFER
+ dma_wd.dma_mode_status = 0x90;
nop();
- dma_wd.fdc_acces_seccount=FDCCMD_RDSEC ;
- udelay (1);
+ if (!(dma_wd.dma_mode_status & 0x01)) {
+ printk( "fd%d: DMA error\n", SelectedDrive );
+ goto err_end;
+ }
+#endif
- fd_nobusy(); /* Wait for IRQ 5 */
+ if (ReqCmd == WRITE && (status & FDCSTAT_WPROT)) {
+ printk( "fd%d: is write protected\n", SelectedDrive );
+ goto err_end;
+ }
+ if ((status & FDCSTAT_RECNF)
+#ifdef TRACKBUFFER
+ /* RECNF is no error after a multiple read when the FDC
+ * searched for a non-existant sector!
+ */
+ && !(ReqCmd == READ && !single_read &&
+ FDC_READ(FDCREG_SECTOR) > unit[SelectedDrive].disktype->spt)
+#endif
+ ) {
+ if (Probing) {
+ if (unit[SelectedDrive].disktype > disk_type) {
+ /* try another disk type */
+ unit[SelectedDrive].disktype--;
+ }
+ else
+ Probing=0;
+ } else {
+/* record not found, but not probing. Maybe stretch wrong ? Restart probing */
+ if (unit[SelectedDrive].autoprobe) {
+ unit[SelectedDrive].disktype = disk_type + NUM_DISK_TYPES-1;
+ Probing = 1;
+ }
+ }
+ if (Probing) {
+ dma_wd.fdc_speed = unit[SelectedDrive].disktype->fdc_speed;
+ setup_req_params( SelectedDrive );
+#ifdef TRACKBUFFER
+ BufferDrive = -1;
+#endif
+ do_fd_action( SelectedDrive );
+ return;
+ }
- restore_flags(flags);
+ printk( "fd%d: sector %d not found\n", SelectedDrive,
+ FDC_READ (FDCREG_SECTOR) );
+ goto err_end;
+ }
+ if (status & FDCSTAT_CRC) {
+ printk( "fd%d: CRC error\n", SelectedDrive );
+ goto err_end;
+ }
+ if (status & FDCSTAT_LOST) {
+ printk( "fd%d: lost data\n", SelectedDrive );
+ goto err_end;
+ }
- fd_deselect(dr);
+ Probing = 0;
- return 0;
+ if (ReqCmd == READ) {
+#ifdef TRACKBUFFER
+ if (single_read)
+ {
+ cache_clear (PhysDMABuffer, 512);
+ copy_buffer (DMABuffer, ReqData);
+ }
+ else
+ {
+ cache_clear (PhysTrackBuffer, MAX_SECTORS * 512);
+ BufferDrive = SelectedDrive;
+ BufferSide = ReqSide;
+ BufferTrack = ReqTrack;
+ copy_buffer (SECTOR_BUFFER (ReqSector), ReqData);
+ }
+#else
+ cache_clear( PhysDMABuffer, 512 );
+ copy_buffer( DMABuffer, ReqData );
+#endif
+ }
+
+ if (++ReqCnt < 2) {
+ /* read next sector */
+ setup_req_params( SelectedDrive );
+ do_fd_action( SelectedDrive );
+ }
+ else {
+ /* all sectors finished */
+ end_request( 1 );
+ redo_fd_request();
+ }
+ return;
+
+ err_end:
+#ifdef TRACKBUFFER
+ BufferDrive = -1;
+ if (ReqCmd == READ && !single_read)
+ {
+ FDC_WRITE (FDCREG_CMD, FDCCMD_FORCI);
+ udelay (40);
+ error_drive = SelectedDrive;
+ error_track = ReqTrack;
+ error_side = ReqSide;
+ setup_req_params (SelectedDrive);
+ do_fd_action (SelectedDrive);
+ return;
+ }
+#endif
+ end_request( 0 );
+ redo_fd_request();
}
+
+/* The (noop) seek operation here is needed to make the WP bit in the
+ * FDC status register accessible for check_change. If the last disk
+ * operation would have been a RDSEC, this bit would always read as 0
+ * no matter what :-( To save time, the seek goes to the track we're
+ * already on.
+ */
+
+static void finish_fdc( void )
+
+{ unsigned long flags;
+
+ TEST_PAGE("finish_fdc",0);
+
+ if (NeedSeek)
+ {
+ FDC_WRITE (FDCREG_DATA, unit[SelectedDrive].track);
+ SET_IRQ_HANDLER (NULL);
+ FDC_WRITE (FDCREG_CMD, FDCCMD_SEEK);
+
+ MotorOn = 1;
+ /* don't wait for IRQ, just go on */
+ }
+
+ if ((timer_active & (1 << FLOPPY_TIMER)) &&
+ timer_table[FLOPPY_TIMER].expires < jiffies + 5)
+ /* If the check for a disk change is done too early after this
+ * last seek command, the WP bit still reads wrong :-((
+ */
+ timer_table[FLOPPY_TIMER].expires = jiffies + 5;
+ else
+ START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
+ del_timer( &motor_off_timer );
+ START_MOTOR_OFF_TIMER( FD_MOTOR_OFF_DELAY );
+
+ save_flags(flags);
+ cli();
+ stdma_release();
+ fdc_busy = 0;
+ wake_up( &fdc_wait );
+ restore_flags(flags);
+
+ DPRINT(("finish_fdc() finished\n"));
+ TEST_PAGE("end of finish_fdc",0);
+}
+
+
/*
* Note that MAX_ERRORS=X doesn't imply that we retry every bad read
* max X times - some types of errors increase the errorcount by 2 or
@@ -372,13 +1003,6 @@
*/
#define MAX_ERRORS 12
-/*
- * The driver is trying to determine the correct media format
- * while probing is set. rw_interrupt() clears it after a
- * successful access.
- */
-static int probing = 0;
-
/* Prevent "aliased" accesses. */
static fd_ref[4] = { 0,0,0,0 };
static fd_device[4] = { 0,0,0,0 };
@@ -392,50 +1016,114 @@
/* Current error count. */
#define CURRENT_ERRORS (CURRENT->errors)
-static void floppy_off (unsigned int nr)
-{
-}
+/* dummy for blk.h */
+static void floppy_off( unsigned int nr) {}
-/*
- * floppy-change is never called from an interrupt, so we can relax a bit
- * here, sleep etc. Note that floppy-on tries to set current_DOR to point
- * to the desired drive, but it will probably not survive the sleep if
- * several floppies are used at the same time: thus the loop.
+/* The detection of disk changes is a dark chapter in Atari history :-(
+ * Because the "Drive ready" signal isn't present in the Atari
+ * hardware, one has to rely on the "Write Protect". This works fine,
+ * as long as no write protected disks are used. TOS solves this
+ * problem by introducing tri-state logic ("maybe changed") and
+ * looking at the serial number in block 0. This isn't possible for
+ * Linux, since the floppy driver can't make assumptions about the
+ * filesystem used on the disk and thus the contents of block 0. I've
+ * choosen the method to always say "The disk was changed" if it is
+ * unsure whether it was. This implies that every open or mount
+ * invalidates the disk buffers if you work with write protected
+ * disks. But at least this is better than working with incorrect data
+ * due to unrecognised disk changes.
*/
-int atari_floppy_change(struct buffer_head * bh)
-{
+
+int atari_floppy_change( struct buffer_head * bh )
+
+{ unsigned int drive = (bh->b_dev & 0x03);
+
+ if (MAJOR(bh->b_dev) != MAJOR_NR) {
+ printk("floppy_changed: not a floppy\n");
+ return 0;
+ }
+
+ if (test_bit (drive, &fake_change)) {
+ /* simulated change (e.g. after formatting) */
+ clear_bit (drive, &fake_change);
+ goto is_changed;
+ }
+ if (test_bit (drive, &changed_floppies)) {
+ /* surely changed (the WP signal changed at least once) */
+ is_changed:
+ clear_bit (drive, &changed_floppies);
+ goto ret_changed;
+ }
+ if (unit[drive].wpstat) {
+ /* WP is on -> could be changed: to be sure, buffers should be
+ * invalidated...
+ */
+ ret_changed:
+#ifdef TRACKBUFFER
+ BufferDrive = -1;
+ error_drive = -1;
+#endif
+
+ unit[drive].disktype = NULL;
+ return 1;
+ }
+
+ /* It doesn't make sense to read or write block 0 (described by
+ * bh) here, because it doesn't answer our question :-(
+ */
+
return 0;
}
+
static __inline__ void copy_buffer(void *from, void *to)
-{
- ulong *p1,*p2;
- int cnt;
- p1 = (ulong *)from;
- p2 = (ulong *)to;
+{ ulong *p1 = (ulong *)from, *p2 = (ulong *)to;
+ int cnt;
- for (cnt = 0; cnt < 512/4; cnt++)
+ for( cnt = 512/4; cnt; cnt-- )
*p2++ = *p1++;
}
+/* This sets up the global variables describing the current request. */
+
+static void setup_req_params( int drive )
+
+{ int block = ReqBlock + ReqCnt;
+
+ ReqTrack = block / unit[drive].disktype->spt;
+ ReqSector = block - ReqTrack * unit[drive].disktype->spt + 1;
+ ReqSide = ReqTrack & 1;
+ ReqTrack >>= 1;
+ ReqData = ReqBuffer + 512 * ReqCnt;
+
+#ifdef TRACKBUFFER
+ if (error_drive == drive
+ && (error_track != ReqTrack || error_side != ReqSide))
+ error_drive = -1;
+#endif
+
+ DPRINT(("Request params: Si=%d Tr=%d Se=%d Data=%08lx\n",ReqSide, ReqTrack, ReqSector, ReqData ));
+}
+
+
static void redo_fd_request(void)
+
{
- unsigned int block, track, sector;
- int device, drive, cnt;
- struct floppy_struct *floppy;
- char *data;
+ int device, drive, type;
+ struct atari_floppy_struct *floppy;
+ TEST_PAGE("redo_fd_request",0);
+ if (CURRENT && CURRENT->dev < 0)
+ goto the_end;
- if (CURRENT && CURRENT->dev < 0) return;
+repeat:
- repeat:
-
- if(!CURRENT)
- return;
+ if (!CURRENT)
+ goto the_end;
if (MAJOR(CURRENT->dev) != MAJOR_NR)
panic(DEVICE_NAME ": request list destroyed");
@@ -445,59 +1133,74 @@
panic(DEVICE_NAME ": block not locked");
}
- probing = 0;
device = MINOR(CURRENT_DEVICE);
+ drive = device & 3;
+ type = device >> 2;
+ floppy = &unit[drive];
+
+ if (!floppy->connected) {
+ /* drive not connected */
+ printk( "Unknown Device: fd%d\n", drive );
+ end_request(0);
+ goto repeat;
+ }
- if (CURRENT_DEVICE == 0x200 ) {
- /* manual selection */
- drive = 0;
- floppy = unit + drive;
+ if (type == 0) {
+ if (!floppy->disktype) {
+ Probing = 1;
+ floppy->disktype = disk_type + NUM_DISK_TYPES-1;
+ floppy->autoprobe = 1;
}
- else
- {
- printk("Unknown Device !\n");
- return;
+ }
+ else {
+ /* user supplied disk type */
+ --type;
+ if (type >= NUM_DISK_TYPES) {
+ printk( "fd%d: invalid disk format", drive );
+ end_request( 0 );
+ goto repeat;
+ }
+ floppy->disktype = &disk_type[type];
+ floppy->autoprobe = 0;
}
- for (cnt = 0; cnt < 2; cnt++) {
- block = CURRENT->sector + cnt;
- if ((int)block > floppy->blocks) {
+ if (CURRENT->sector + 1 > floppy->disktype->blocks) {
end_request(0);
goto repeat;
}
- track = block / floppy->dtype->sects;
- sector = block - track * floppy->dtype->sects;
- data = CURRENT->buffer + 512 * cnt;
+ /* stop deselect timer */
+ del_timer( &motor_off_timer );
+ ReqCnt = 0;
+ ReqCmd = CURRENT->cmd;
+ ReqBlock = CURRENT->sector;
+ ReqBuffer = CURRENT->buffer;
+ setup_req_params( drive );
+ do_fd_action( drive );
- switch (CURRENT->cmd) {
- case READ:
- atari_read(device,track,sector);
- copy_buffer(trackdata,data);
- break;
+ return;
- case WRITE:
- copy_buffer(data,trackdata);
- atari_write(device,track,sector);
- break;
+ the_end:
+ finish_fdc();
+}
- default:
- printk("do_fd_request: unknown command\n");
- end_request(0);
- goto repeat;
- }
- }
- end_request(1);
- goto repeat;
-}
+void do_fd_request(void)
+
+{ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ while( fdc_busy ) sleep_on( &fdc_wait );
+ fdc_busy = 1;
+ stdma_lock( floppy_irq, 0 );
+ restore_flags(flags);
-static void do_fd_request(void)
-{
redo_fd_request();
}
+
static int fd_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long param)
{
@@ -505,53 +1208,102 @@
return -EINVAL;
}
-/*======================================================================
- Return unit ID number of given disk
-======================================================================*/
-#ifdef __notneeded__
-static unsigned long get_drive_id(int drive)
-{
- return FD_HD_3;
-}
-#endif
-static void fd_probe(int drive)
+/* Initialize the 'unit' variable for drive 'drive' */
+
+static void fd_probe( int drive )
{
- unit[drive].type = NULL;
- if (drive != 0)
- /* At the moment, only one floppy drive is supported */
+ unit[drive].connected = 0;
+ unit[drive].disktype = NULL;
+
+ if (!fd_test_drive_present( drive ))
return;
-#ifdef CONFIG_FLOPPY_DD_ONLY
- unit[drive].type = &drive_types[1]; /* DD */
- dma_wd.fdc_speed = 0;
-#else
- unit[drive].type = &drive_types[0]; /* HD */
- dma_wd.fdc_speed = 3;
-#endif
+ unit[drive].connected = 1;
+ unit[drive].track = 0;
+ unit[drive].steprate = FDCSTEP_3;
+ MotorOn = 1; /* from probe restore operation! */
+}
+
+
+/* This function tests the physical presence of a floppy drive (not
+ * whether a disk is inserted). This is done by issuing a restore
+ * command, waiting max. 2 seconds (that should be enough to move the
+ * head across the whole disk) and looking at the state of the "TR00"
+ * signal. This should now be raised if there is a drive connected
+ * (and there is no hardware failure :-) Otherwise, the drive is
+ * declared absent.
+ */
+
+static int fd_test_drive_present( int drive )
+
+{ unsigned long timeout;
+ unsigned char status;
+ int ok;
+
+ if (drive > 1) return( 0 );
+ fd_select_drive( drive );
+
+ /* disable interrupt temporarily */
+ mfp.int_en_b &= 0x7f;
+ FDC_WRITE( FDCREG_CMD, FDCCMD_RESTORE | FDCSTEP_6 );
+
+ for( ok = 0, timeout = jiffies + 2*HZ+HZ/2; jiffies < timeout; ) {
+ if (!(mfp.par_dt_reg & 0x20))
+ break;
+ }
+
+ status = FDC_READ( FDCREG_STATUS );
+ ok = (status & FDCSTAT_TR00) != 0;
- unit[drive].dtype = &data_types[0]; /* only one type */
- unit[drive].track = -1;
+ /* force interrupt to abort restore operation (FDC would try
+ * about 50 seconds!) */
+ FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );
+ udelay(40);
+ status = FDC_READ( FDCREG_STATUS );
+ udelay(20);
+
+ if (ok) {
+ /* dummy seek command to make WP bit accessible */
+ FDC_WRITE( FDCREG_DATA, 0 );
+ FDC_WRITE( FDCREG_CMD, FDCCMD_SEEK );
+ while( mfp.par_dt_reg & 0x20 )
+ ;
+ status = FDC_READ( FDCREG_STATUS );
+ }
- unit[drive].sects = unit[drive].dtype->sects * unit[drive].type->sect_mult;
- unit[drive].blocks = unit[drive].type->heads * unit[drive].type->tracks *
- unit[drive].sects;
+ mfp.int_pn_b = 0x7f;
+ mfp.int_en_b |= 0x80;
- unit[drive].disk = -1;
- unit[drive].motor = 0;
- unit[drive].busy = 0;
- unit[drive].status = -1;
+ return( ok );
}
-static void config_types(void)
+
+/* Look how many and which kind of drives are connected. If there are
+ * floppies, additionally start the disk-change and motor-off timers.
+ */
+
+static void config_types( void )
+
{
- int drive;
+ int drive, cnt = 0;
+
+ /* for probing drives, set the FDC speed to 8 MHz */
+ dma_wd.fdc_speed = 0;
printk("Probing floppy drive(s):\n");
- for (drive = 0; drive < FD_MAX_UNITS; drive++) {
- fd_probe(drive);
- if (unit[drive].type != NULL)
- printk("%d: %s\n", drive, unit[drive].type->name);
+ for( drive = 0; drive < FD_MAX_UNITS; drive++ ) {
+ fd_probe( drive );
+ if (unit[drive].connected) {
+ printk("fd%d\n", drive);
+ ++cnt;
+ }
+ }
+
+ if (cnt > 0) {
+ START_MOTOR_OFF_TIMER( FD_MOTOR_OFF_DELAY );
+ if (cnt == 1) fd_select_drive( 0 );
+ START_CHECK_CHANGE_TIMER( CHECK_CHANGE_DELAY );
}
}
@@ -560,7 +1312,9 @@
* /dev/PS0 etc), and disallows simultaneous access to the same
* drive with different device numbers.
*/
-static int floppy_open(struct inode *inode, struct file *filp)
+
+static int floppy_open( struct inode *inode, struct file *filp )
+
{
int drive;
int old_dev;
@@ -578,16 +1332,24 @@
if (old_dev && old_dev != inode->i_rdev)
invalidate_buffers(old_dev);
- if (filp && filp->f_mode)
- check_disk_change(inode->i_rdev);
-
+ if (filp && filp->f_mode) {
+ check_disk_change( inode->i_rdev );
+ if (filp->f_mode & 2) {
+ if (unit[drive].wpstat) {
+ floppy_release(inode, filp);
+ return -EROFS;
+ }
+ }
+ }
return 0;
}
-static void floppy_release(struct inode * inode, struct file * filp)
+
+static void floppy_release( struct inode * inode, struct file * filp )
+
{
- sync_dev(inode->i_rdev);
+ fsync_dev(inode->i_rdev);
if (!fd_ref[inode->i_rdev & 3]--) {
printk("floppy_release with fd_ref == 0");
fd_ref[inode->i_rdev & 3] = 0;
@@ -607,25 +1369,37 @@
block_fsync /* fsync */
};
-#ifdef __notneeded__
-static void fd_block_done(struct intframe *fp, void *data)
-{
-}
-#endif
void atari_floppy_init(void)
-{
- int i;
+
+{ int i;
if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
printk("Unable to get major %d for floppy\n",MAJOR_NR);
return;
}
+
/* initialize variables */
- selected = -1;
+ SelectedDrive = -1;
+#ifdef TRACKBUFFER
+ BufferDrive = -1;
+ error_drive = -1;
+#endif
- /* memory returned by atari_stram_alloc is identity mapped */
- trackdata = atari_stram_alloc (512);
+ /* initialize motor-off timer */
+ timer_table[FLOPPY_TIMER].fn = check_change;
+ timer_active &= ~(1 << FLOPPY_TIMER);
+
+ /* The ST-Ram buffers are now allocated in
+ * atari_floppy_alloc_buffers(), which is called by
+ * blk_dev_init(). This is because floppy_init() is called after
+ * mem_init() and stram_alloc() isn't possible any more here.
+ */
+ PhysDMABuffer = (unsigned long) VTOP(DMABuffer);
+#ifdef TRACKBUFFER
+ PhysTrackBuffer = (unsigned long) VTOP(TrackBuffer);
+ BufferDrive = BufferSide = BufferTrack = -1;
+#endif
for (i = 0; i < FD_MAX_UNITS; i++) {
unit[i].track = -1;
@@ -636,3 +1410,25 @@
config_types();
}
+
+
+/* This function is called by blk_dev_init() to give the floppy driver
+ * a chance to allocate some ST-Ram
+ */
+
+unsigned long atari_floppy_alloc_buffers( unsigned long mem_start )
+
+{
+#ifdef TRACKBUFFER
+ DMABuffer = atari_stram_alloc( (MAX_SECTORS+1)*512, &mem_start );
+ TrackBuffer = DMABuffer + 512;
+#else
+ DMABuffer = atari_stram_alloc( 512, &mem_start );
+#endif
+ return( mem_start );
+}
+
+
+/* Local Variables: */
+/* tab-width: 4 */
+/* End: */
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/block/blk.h linux-0.9pl4/drivers/block/blk.h
--- linux-0.9pl3/drivers/block/blk.h Sun Aug 14 10:30:43 1994
+++ linux-0.9pl4/drivers/block/blk.h Mon Nov 7 22:13:16 1994
@@ -27,8 +27,8 @@
/*
* Ok, this is an expanded form so that we can use the same
* request for paging requests when that is implemented. In
- * paging, 'bh' is NULL, and 'waiting' is used to wait for
- * read/write completion.
+ * paging, 'bh' is NULL, and the semaphore is used to wait
+ * for read/write completion.
*/
struct request {
int dev; /* -1 if no request */
@@ -38,7 +38,7 @@
unsigned long nr_sectors;
unsigned long current_nr_sectors;
char * buffer;
- struct task_struct * waiting;
+ struct semaphore * sem;
struct buffer_head * bh;
struct buffer_head * bhtail;
struct request * next;
@@ -205,6 +205,15 @@
#define DEVICE_ON(device)
#define DEVICE_OFF(device)
+#elif (MAJOR_NR == ACSI_MAJOR)
+
+#define DEVICE_NAME "ACSI"
+#define DEVICE_INTR do_acsi
+#define DEVICE_REQUEST do_acsi_request
+#define DEVICE_NR(device) (MINOR(device) >> 4)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
#else
#error "unknown blk device"
@@ -252,7 +261,6 @@
{
struct request * req;
struct buffer_head * bh;
- struct task_struct * p;
req = CURRENT;
req->errors = 0;
@@ -270,6 +278,7 @@
req->bh = bh->b_reqnext;
bh->b_reqnext = NULL;
bh->b_uptodate = uptodate;
+ if (!uptodate) bh->b_req = 0; /* So no "Weird" errors */
unlock_buffer(bh);
if ((bh = req->bh) != NULL) {
req->current_nr_sectors = bh->b_size >> 9;
@@ -283,12 +292,8 @@
}
DEVICE_OFF(req->dev);
CURRENT = req->next;
- if ((p = req->waiting) != NULL) {
- req->waiting = NULL;
- p->state = TASK_RUNNING;
- if (p->counter > current->counter)
- need_resched = 1;
- }
+ if (req->sem != NULL)
+ up(req->sem);
req->dev = -1;
wake_up(&wait_for_request);
}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/block/falhd.c linux-0.9pl4/drivers/block/falhd.c
--- linux-0.9pl3/drivers/block/falhd.c Tue Sep 27 22:21:42 1994
+++ linux-0.9pl4/drivers/block/falhd.c Mon Nov 7 22:14:45 1994
@@ -20,11 +20,6 @@
* Modified 1994 for ATARI IDE controller support by Bjoern Brauel
*/
-/*
- * 08/08/94 changes for proper Seagate recognition, debug messages
- * by Helmut Neukirchen, hn@pool.informatik.rwth-aachen
- */
-
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/sched.h>
@@ -38,6 +33,7 @@
#include <linux/atarihw.h>
#include <linux/atarihdreg.h>
#include <linux/atariints.h>
+#include <linux/atari_stdma.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -53,6 +49,7 @@
#define RECAL_FREQ 4 /* Recalibrate every 4th retry */
#define MAX_HD 2
+extern void hd_interrupt (struct intframe *, void *);
static void recal_intr(void);
static void bad_rw_intr(void);
@@ -70,7 +67,7 @@
struct hd_i_struct {
unsigned int head,sect,cyl,wpcom,lzone,ctl;
};
-static struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
+struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
static int NR_HD = 0;
static struct hd_struct hd[MAX_HD<<6]={{0,0},};
@@ -282,7 +279,7 @@
* doing a reset and a retry seems to result in an eternal loop. Right now I
* ignore it, and just set the timeout.
*/
-static void unexpected_hd_interrupt(void)
+void unexpected_hd_interrupt(void)
{
printk("Unexpected HD interrupt\n");
SET_TIMER;
@@ -357,8 +354,9 @@
MINOR(CURRENT->dev), CURRENT->sector, i, CURRENT->
buffer);
#endif
- if (!i || (CURRENT->bh && !SUBSECTOR(i)))
+ if (!i || (CURRENT->bh && !SUBSECTOR(i))) {
end_request(1);
+ }
if (i > 0) {
SET_INTR(&read_intr);
return;
@@ -398,8 +396,9 @@
i = --CURRENT->nr_sectors;
--CURRENT->current_nr_sectors;
CURRENT->buffer += 512;
- if (!i || (CURRENT->bh && !SUBSECTOR(i)))
+ if (!i || (CURRENT->bh && !SUBSECTOR(i))) {
end_request(1);
+ }
if (i > 0) {
SET_INTR(&write_intr);
port_write(HD_DATA,CURRENT->buffer,15);
@@ -462,7 +461,7 @@
nsect = CURRENT->nr_sectors;
if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) {
#ifdef DEBUG
- printk("hd : attempted read for sector %d past end of device at sector %d.\n",
+ printk("hd%d : attempted read for sector %d past end of device at sector %d.\n",
block, hd[dev].nr_sects);
#endif
end_request(0);
@@ -604,33 +603,26 @@
NULL /* next */
};
-/*te******************************************************************
+/*******************************************************************
*
* hd_interrupt routine
* Test, if this is a harddisk interrupt and call
* the irq handler
* Otherwise ignore this interrupt.
*
- ********************************************************/
-static void hd_interrupt (struct intframe *fp, void *data)
+ *******************************************************************/
+extern void hd_interrupt (struct intframe *fp, void *data)
{
-void (*hd_irq_handler)(void) = DEVICE_INTR;
+ void (*hd_irq_handler)(void) = DEVICE_INTR;
-/* Test, if this is a harddisk interrupt. MSB(0xdd2030) = 1 (Amiga only) */
-/* GK: this has to be changed for Atari FALCON.
- * Is there any way to determine if harddisk did interrupt ?
- */
-if (1 /*inb (HD_IRQ_TEST) & 0x7f*/)
- {
DEVICE_INTR = NULL;
timer_active &= ~(1 << HD_TIMER);
- if (hd_irq_handler)
-/* hd_irq_handler = unexpected_hd_interrupt;*/
+ if (!hd_irq_handler)
+ hd_irq_handler = unexpected_hd_interrupt;
hd_irq_handler ();
return;
- }
}
/*te******************************************************************
@@ -671,12 +663,9 @@
/* Test, if ready to read */
for (i=0; i<HD_ID_RETRIES; i++)
{
- if ((inb_p(HD_STATUS) & (DRQ_STAT|READY_STAT)) == (DRQ_STAT|READY_STAT)) /* ++hn: Detect Seagate drives properly */
+ if (inb_p (HD_STATUS) & DRQ_STAT)
{
drive_found = 1;
-#ifdef DEBUG
- printk("hd%d: WIN_IDENTIFY: status = 0x%hx\n", drive, inb_p(HD_STATUS));
-#endif
break;
}
}
@@ -693,31 +682,26 @@
hd_info[drive].sect = Identify [6];
NR_HD++;
Identify [47] = 0x0000;
- printk ("hd%c: %s\n", (char)drive+'a', (unsigned char *)&Identify [27]); /* ++hn: use hda/hdb naming for the user-messages */
+ printk ("hd%d: %s\n", drive, (unsigned char *)&Identify [27]);
printk (" cyl %d, sector %d, head %d.\n",
hd_info[drive].cyl,
hd_info[drive].sect,
hd_info[drive].head);
}
else
- printk ("hd%c not found.\n", (char)drive+'a'); /* ++hn: use hda/hdb naming for the user-messages */
+ printk ("hd%d not found.\n", drive);
}
sti (); /* Enable interrupts */
/* Add the interrupt handler */
if (NR_HD)
-{
- if (!add_isr (IRQ_MFP_FDC, hd_interrupt, 0, NULL))
+/* if (!add_isr (IRQ_MFP_FDC, hd_interrupt, 0, NULL))
{
printk ("HD: Can't add interrupt handler for harddisk device.\n");
NR_HD = 0;
- }
- else
- {
+ } */
mfp.int_en_b |= 0x80; /* enable int */
mfp.int_mk_b |= 0x80; /* not masked */
- }
-}
i = NR_HD;
while (i-- > 0)
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/block/ll_rw_blk.c linux-0.9pl4/drivers/block/ll_rw_blk.c
--- linux-0.9pl3/drivers/block/ll_rw_blk.c Sun Aug 14 10:30:43 1994
+++ linux-0.9pl4/drivers/block/ll_rw_blk.c Mon Nov 7 22:15:16 1994
@@ -29,6 +29,14 @@
extern u_long sbpcd_init(u_long, u_long);
#endif CONFIG_SBPCD
+#ifdef CONFIG_ATARI_ACSI
+extern u_long acsi_init(u_long, u_long);
+#endif CONFIG_ATARI_ACSI
+
+#ifdef CONFIG_ATARI
+#include <linux/atarihw.h> /* for atari_stram_alloc() */
+#endif
+
/*
* The request-struct contains all necessary data
* to load a nr of sectors into memory
@@ -234,16 +242,16 @@
* they start processing an entry. For this reason it is safe to continue
* to add links to the top entry for scsi devices.
*/
- if ((major == HD_MAJOR
+ if ((major == HD_MAJOR || major == ACSI_MAJOR
|| major == SCSI_DISK_MAJOR
|| major == SCSI_CDROM_MAJOR)
&& (req = blk_dev[major].current_request))
{
- if (major == HD_MAJOR)
+ if (major == HD_MAJOR || major == ACSI_MAJOR)
req = req->next;
while (req) {
if (req->dev == bh->b_dev &&
- !req->waiting &&
+ !req->sem &&
req->cmd == rw &&
req->sector + req->nr_sectors == sector &&
req->nr_sectors < 254)
@@ -257,7 +265,7 @@
}
if (req->dev == bh->b_dev &&
- !req->waiting &&
+ !req->sem &&
req->cmd == rw &&
req->sector - count == sector &&
req->nr_sectors < 254)
@@ -302,7 +310,7 @@
req->nr_sectors = count;
req->current_nr_sectors = count;
req->buffer = bh->b_data;
- req->waiting = NULL;
+ req->sem = NULL;
req->bh = bh;
req->bhtail = bh;
req->next = NULL;
@@ -313,6 +321,7 @@
{
struct request * req;
unsigned int major = MAJOR(dev);
+ struct semaphore sem = MUTEX_LOCKED;
if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) {
printk("Trying to read nonexistent block-device %04x (%d)\n",dev,page*8);
@@ -334,12 +343,11 @@
req->nr_sectors = 8;
req->current_nr_sectors = 8;
req->buffer = buffer;
- req->waiting = current;
+ req->sem = &sem;
req->bh = NULL;
req->next = NULL;
- current->state = TASK_SWAPPING;
add_request(major+blk_dev,req);
- schedule();
+ down(&sem);
}
/* This function can be used to request a number of buffers from a block
@@ -441,6 +449,7 @@
int buffersize;
struct request * req;
unsigned int major = MAJOR(dev);
+ struct semaphore sem = MUTEX_LOCKED;
if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) {
printk("ll_rw_swap_file: trying to swap nonexistent block-device\n");
@@ -469,12 +478,11 @@
req->nr_sectors = buffersize >> 9;
req->current_nr_sectors = buffersize >> 9;
req->buffer = buf;
- req->waiting = current;
+ req->sem = &sem;
req->bh = NULL;
req->next = NULL;
- current->state = TASK_UNINTERRUPTIBLE;
add_request(major+blk_dev,req);
- schedule();
+ down(&sem);
}
}
@@ -508,7 +516,21 @@
#ifdef CONFIG_SBPCD
mem_start = sbpcd_init(mem_start, mem_end);
#endif CONFIG_SBPCD
+#ifdef CONFIG_ATARI_ACSI
+ mem_start = acsi_init(mem_start, mem_end);
+#endif CONFIG_ATARI_ACSI
if (boot_info.ramdisk_size)
mem_start += rd_init(mem_start, boot_info.ramdisk_size*1024);
+#ifdef CONFIG_ATARI
+ /* ++roman: Call a function of the Atari floppy driver here that
+ * allocates some ST-Ram buffers, because atari_stram_alloc()
+ * isn't possible in atari_floppy_init() any more.
+ */
+ if (boot_info.machtype == MACH_ATARI) {
+ extern unsigned long
+ atari_floppy_alloc_buffers( unsigned long mem_start );
+ mem_start = atari_floppy_alloc_buffers( mem_start );
+ }
+#endif
return mem_start;
}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/char/atari_SCC.c linux-0.9pl4/drivers/char/atari_SCC.c
--- linux-0.9pl3/drivers/char/atari_SCC.c Sun Aug 14 10:30:41 1994
+++ linux-0.9pl4/drivers/char/atari_SCC.c Mon Nov 21 18:09:01 1994
@@ -25,11 +25,11 @@
#include <linux/atariints.h>
#include "serial.h"
-#include "atari_MFPser.h"
+#include "atari_SCC.h"
void atari_init_SCC( struct async_struct *info, SERTYPE type,
- int tt_flag, void *ri_addr,
+ int channel, void *ri_addr,
unsigned char ri_bitno, unsigned char ri_active )
{
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/char/atari_SCC.h linux-0.9pl4/drivers/char/atari_SCC.h
--- linux-0.9pl3/drivers/char/atari_SCC.h Sun Sep 25 16:19:40 1994
+++ linux-0.9pl4/drivers/char/atari_SCC.h Mon Nov 21 18:09:02 1994
@@ -314,7 +314,7 @@
/***************************** Prototypes *****************************/
-void atari_init_SCC( struct async_struct *info, SERTYPE type, int tt_flag,
+void atari_init_SCC( struct async_struct *info, SERTYPE type, int channel,
void *ri_addr, unsigned char ri_bitno, unsigned char
ri_active );
@@ -337,6 +337,7 @@
* I'm not sure, correct me please!), that gives 4 nops for a TT (32
* MHz) (2 would be sufficient for the Falcon (16 MHz), but looking at
* boot_info.bi_atari.model at runtime takes longer than 2 nop's...)
+ * ++andreas: nop needs only 2 cycles, seven of them are needed.
*/
static __inline__ void scc_reg_delay( void )
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/char/atarimouse.c linux-0.9pl4/drivers/char/atarimouse.c
--- linux-0.9pl3/drivers/char/atarimouse.c Sun Aug 14 10:30:41 1994
+++ linux-0.9pl4/drivers/char/atarimouse.c Mon Nov 21 18:09:02 1994
@@ -1,6 +1,11 @@
/*
* Atari Mouse Driver for Linux
* by Robert de Vries (robert@and.nl) 19Jul93
+ *
+ * 16 Nov 1994 Andreas Schwab
+ * Compatibility with busmouse
+ * Support for three button mouse (shamelessly stolen from MiNT)
+ * third button wired to one of the joystick directions on joystick 1
*/
#include <linux/sched.h>
@@ -11,14 +16,21 @@
#include <asm/segment.h>
static struct mouse_status mouse;
+int atari_mouse_buttons;
void atari_mouse_interrupt(char *buf)
{
+ int buttons;
+
/* ikbd_mouse_disable(); */
- mouse.buttons = buf[0] & 0x3;
- mouse.dx = buf[1];
- mouse.dy = buf[2];
+ buttons = ((buf[0] & 1 ? 1 : 0)
+ | (buf[0] & 2 ? 4 : 0)
+ | (atari_mouse_buttons & 2));
+ atari_mouse_buttons = buttons;
+ mouse.buttons = ~buttons & 7;
+ mouse.dx += buf[1];
+ mouse.dy += buf[2];
mouse.ready = 1;
wake_up_interruptible(&mouse.wait);
@@ -43,6 +55,10 @@
return -EBUSY;
mouse.active = 1;
mouse.ready = 0;
+ mouse.dx = mouse.dy = 0;
+ atari_mouse_buttons = 0;
+ ikbd_mouse_y0_bot ();
+ ikbd_mouse_thresh (1, 1);
ikbd_mouse_rel_pos();
return 0;
}
@@ -54,21 +70,32 @@
static int read_mouse(struct inode *inode, struct file *file, char *buffer, int count)
{
- int i;
+ int dx, dy, buttons;
if (count < 3)
return -EINVAL;
if (!mouse.ready)
return -EAGAIN;
/* ikbd_mouse_disable */
- put_fs_byte(mouse.buttons, buffer++);
- put_fs_byte(mouse.dx, buffer++);
- put_fs_byte(mouse.dy, buffer++);
- for (i = 3; i < count; i++)
- put_fs_byte(0, buffer++);
+ dx = mouse.dx;
+ dy = mouse.dy;
+ buttons = mouse.buttons;
+ if (dx > 127)
+ dx = 127;
+ else if (dx < -128)
+ dx = -128;
+ if (dy > 127)
+ dy = 127;
+ else if (dy < -128)
+ dy = -128;
+ mouse.dx -= dx;
+ mouse.dy -= dy;
mouse.ready = 0;
/* ikbd_mouse_rel_pos(); */
- return i;
+ put_fs_byte(buttons | 0x80, buffer++);
+ put_fs_byte((char) dx, buffer++);
+ put_fs_byte((char) dy, buffer++);
+ return 3;
}
static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table *wait)
Binary files linux-0.9pl3/drivers/char/bdflush-1.4.tar.gz and linux-0.9pl4/drivers/char/bdflush-1.4.tar.gz differ
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/char/console.c linux-0.9pl4/drivers/char/console.c
--- linux-0.9pl3/drivers/char/console.c Sun Aug 14 10:30:40 1994
+++ linux-0.9pl4/drivers/char/console.c Mon Nov 21 18:09:03 1994
@@ -82,7 +82,9 @@
static void clear_selection(void);
/* Variables for selection control. */
-#define SEL_BUFFER_SIZE TTY_BUF_SIZE
+/* The original size (1024) is to small for my console - FN */
+#define SEL_BUFFER_SIZE 4096
+/* #define SEL_BUFFER_SIZE TTY_BUF_SIZE */
static int sel_cons;
static int sel_start = -1;
static int sel_end;
@@ -93,8 +95,7 @@
extern void register_console(void (*proc)(const char *));
extern void compute_shiftstate(void);
-static int console_blanked = 0;
-static int can_do_color = 0;
+int console_blanked = 0;
static int printable = 0;
struct condata vc_cons[NR_CONSOLES];
@@ -105,6 +106,7 @@
#define y (vc_cons[currcons].vc_y)
#define top (vc_cons[currcons].vc_top)
#define bottom (vc_cons[currcons].vc_bottom)
+#define pos (vc_cons[currcons].vc_pos)
/*
* Arno:
* On the 680x0 we could have screens with different sizes (at least
@@ -112,6 +114,7 @@
* of using a global variable like the original PC code.
*/
#define video_num_columns (vc_cons[currcons].vc_cols)
+#define video_size_row (vc_cons[currcons].vc_size_row)
#define video_num_lines (vc_cons[currcons].vc_rows)
#define state (vc_cons[currcons].vc_state)
#define npar (vc_cons[currcons].vc_npar)
@@ -125,6 +128,7 @@
#define G1_charset (vc_cons[currcons].vc_G1_charset)
#define saved_G0 (vc_cons[currcons].vc_saved_G0)
#define saved_G1 (vc_cons[currcons].vc_saved_G1)
+#define video_mem_start (vc_cons[currcons].vc_video_mem_start)
#define video_erase_char (vc_cons[currcons].vc_video_erase_char)
#define decscnm (vc_cons[currcons].vc_decscnm)
#define decom (vc_cons[currcons].vc_decom)
@@ -132,6 +136,7 @@
#define deccm (vc_cons[currcons].vc_deccm)
#define decim (vc_cons[currcons].vc_decim)
#define need_wrap (vc_cons[currcons].vc_need_wrap)
+#define can_do_color (vc_cons[currcons].vc_can_do_color)
#define color (vc_cons[currcons].vc_color)
#define s_color (vc_cons[currcons].vc_s_color)
#define def_color (vc_cons[currcons].vc_def_color)
@@ -281,6 +286,7 @@
y = max_y - 1;
else
y = new_y;
+ pos = video_mem_start + y * video_num_columns + x;
need_wrap = 0;
}
@@ -319,9 +325,22 @@
static void scrup(int currcons, unsigned int t, unsigned int b,
int nr)
{
+ unsigned short *p;
+ int i;
+
if (b > video_num_lines || t >= b)
return;
+ memmove (video_mem_start + t * video_num_columns,
+ video_mem_start + (t + nr) * video_num_columns,
+ (b - t - nr) * video_num_columns * 2);
+
+ p = video_mem_start + (b - nr) * video_num_columns;
+ for (i = nr * video_num_columns; i > 0; i--)
+ *p++ = video_erase_char;
+
+ if (currcons != fg_console)
+ return;
/*
* Arno:
* Scrolling has now been moved to amicon.c where it should have
@@ -336,9 +355,22 @@
static void scrdown(int currcons, unsigned int t, unsigned int b,
int nr)
{
+ unsigned short *p;
+ int i;
+
if (b > video_num_lines || t >= b)
return;
+ memmove (video_mem_start + (t + nr) * video_num_columns,
+ video_mem_start + t * video_num_columns,
+ (b - t - nr) * video_num_columns * 2);
+
+ p = video_mem_start + t * video_num_columns;
+ for (i = nr * video_num_columns; i > 0; i--)
+ *p++ = video_erase_char;
+
+ if (currcons != fg_console)
+ return;
/*
* Arno:
* Scrolling has now been moved to amicon.c where it should have
@@ -353,6 +385,7 @@
{
if (y+1<bottom) {
y++;
+ pos += video_num_columns;
return;
} else
scrup(currcons,top,bottom, 1);
@@ -363,6 +396,7 @@
{
if (y>top) {
y--;
+ pos -= video_num_columns;
return;
} else
scrdown(currcons,top,bottom, 1);
@@ -371,12 +405,14 @@
static inline void cr(int currcons)
{
+ pos -= x;
need_wrap = x = 0;
}
static inline void bs(int currcons)
{
if (x) {
+ pos--;
x--;
need_wrap = 0;
}
@@ -396,41 +432,77 @@
static void csi_J(int currcons, int vpar)
{
+ unsigned long count;
+ unsigned short *start;
+
switch (vpar) {
case 0: /* erase from cursor to end of display */
+ count = (video_mem_start
+ + video_num_columns * video_num_lines
+ - pos);
+ start = pos;
+ if (currcons != fg_console)
+ break;
/* 680x0 do in two stages */
sw->con_clear(&vc_cons[currcons],y,x,1,video_num_columns-x);
sw->con_clear(&vc_cons[currcons],y+1,0,video_num_lines-y-1, video_num_columns);
break;
case 1: /* erase from start to cursor */
+ count = pos - video_mem_start + 1;
+ start = video_mem_start;
+ if (currcons != fg_console)
+ break;
/* 680x0 do in two stages */
sw->con_clear(&vc_cons[currcons],0,0,y, video_num_columns);
sw->con_clear(&vc_cons[currcons],y,0,1,x + 1);
break;
case 2: /* erase whole display */
+ count = video_num_columns * video_num_lines;
+ start = video_mem_start;
+ if (currcons != fg_console)
+ break;
sw->con_clear(&vc_cons[currcons],0,0,video_num_lines, video_num_columns);
break;
default:
return;
}
+ while (count-- > 0)
+ *start++ = video_erase_char;
need_wrap = 0;
}
static void csi_K(int currcons, int vpar)
{
+ unsigned long count;
+ unsigned short *start;
+
switch (vpar) {
case 0: /* erase from cursor to end of line */
+ count = video_num_columns - x;
+ start = pos;
+ if (currcons != fg_console)
+ break;
sw->con_clear(&vc_cons[currcons],y,x,1,video_num_columns-x);
break;
case 1: /* erase from start of line to cursor */
+ start = pos - x;
+ count = x + 1;
+ if (currcons != fg_console)
+ break;
sw->con_clear(&vc_cons[currcons],y,0,1,x + 1);
break;
case 2: /* erase whole line */
+ start = pos - x;
+ count = video_num_columns;
+ if (currcons != fg_console)
+ break;
sw->con_clear(&vc_cons[currcons],y,0,1,video_num_columns);
break;
default:
return;
}
+ while (count-- > 0)
+ *start++ = video_erase_char;
need_wrap = 0;
}
@@ -444,28 +516,39 @@
* seems hardware independent, but uses the EGA/VGA way of representing
* attributes.
* TODO: modify for 680x0 and add attribute processing to putc code.
+ *
+ * ++roman: I completely changed the attribute format for monochrome
+ * mode (!can_do_color). The formerly used MDA (monochrome display
+ * adapter) format didn't allow the combination of certain effects.
+ * Now the attribute is just a bit vector:
+ * Bit 0..1: intensity (0..2)
+ * Bit 2 : underline
+ * Bit 3 : reverse
+ * Bit 7 : blink
*/
static void update_attr(int currcons)
{
+ if (!can_do_color) {
+ /* Special treatment for monochrome */
+ attr = intensity |
+ (underline ? 4 : 0) |
+ ((reverse ^ decscnm) ? 8 : 0) |
+ (blink ? 0x80 : 0);
+ video_erase_char = ' ' | ((reverse ^ decscnm) ? 0x800 : 0);
+ return;
+ }
+
attr = color;
- if (can_do_color) {
if (underline)
attr = (attr & 0xf0) | ulcolor;
else if (intensity == 0)
attr = (attr & 0xf0) | halfcolor;
- }
if (reverse ^ decscnm)
attr = (attr & 0x88) | (((attr >> 4) | (attr << 4)) & 0x77);
if (blink)
attr ^= 0x80;
if (intensity == 2)
attr ^= 0x08;
- if (!can_do_color) {
- if (underline)
- attr = (attr & 0xf8) | 0x01;
- else if (intensity == 0)
- attr = (attr & 0xf0) | 0x08;
- }
if (decscnm)
video_erase_char = (((color & 0x88) | (((color >> 4) | (color << 4)) & 0x77)) << 8) | ' ';
else
@@ -676,6 +759,17 @@
static void insert_char(int currcons)
{
+ int i;
+ unsigned short *p = pos;
+
+ for (i = video_num_columns - x - 2; i >= 0; i--)
+ p[i + 1] = p[i];
+ *pos = video_erase_char;
+ need_wrap = 0;
+
+ if (currcons != fg_console)
+ return;
+
/* Arno:
* Move the remainder of the line (-1 character) one spot to the right
*/
@@ -683,23 +777,34 @@
/*
* Print the erase char on the current position
*/
- sw->con_putc(&vc_cons[currcons],(video_erase_char & 0x00ff),y,x,reverse ? DM_INVERSE : DM_COPY);
-
- need_wrap = 0;
+ sw->con_putc(&vc_cons[currcons],(video_erase_char & 0x00ff),y,x);
}
static void csi_at(int currcons, unsigned int nr)
{
+ int i;
+ unsigned short *p;
+
if (nr > video_num_columns - x)
nr = video_num_columns - x;
else if (!nr)
nr = 1;
+
+ p = pos + video_num_columns - x - nr;
+ while (--p >= pos)
+ p[nr] = *p;
+ for (i = 0; i < nr; i++)
+ *++p = video_erase_char;
+ need_wrap = 0;
+
+ if (currcons != fg_console)
+ return;
+
sw->con_bmove (&vc_cons[currcons], y, x, y, x + nr,
1, video_num_columns - x - nr);
while (nr--)
sw->con_putc (&vc_cons[currcons], video_erase_char & 0x00ff,
- y, x + nr, reverse ? DM_INVERSE : DM_COPY);
- need_wrap = 0;
+ y, x + nr);
}
static void csi_L(int currcons, unsigned int nr)
@@ -714,20 +819,31 @@
static void csi_P(int currcons, unsigned int nr)
{
+ int i;
+ unsigned short *p, *end;
+
if (nr > video_num_columns - x)
nr = video_num_columns - x;
else if (!nr)
nr = 1;
+ p = pos;
+ end = pos + video_num_columns - x - nr;
+ while (p < end)
+ *p = p[nr], p++;
+ for (i = 0; i < nr; i++)
+ *p++ = video_erase_char;
+ need_wrap = 0;
+
+ if (currcons != fg_console)
+ return;
+
sw->con_bmove (&vc_cons[currcons], y, x + nr, y, x,
1, video_num_columns - x - nr);
while (nr--)
sw->con_putc (&vc_cons[currcons], video_erase_char & 0x00ff,
- y, video_num_columns - 1 - nr, reverse ? DM_INVERSE
- : DM_COPY);
-
- need_wrap = 0;
+ y, video_num_columns - 1 - nr);
}
static void csi_M(int currcons, unsigned int nr)
@@ -829,6 +945,11 @@
printk("con_write: illegal tty (%d)\n", currcons);
return;
}
+
+ /* undraw cursor first */
+ if (currcons == fg_console)
+ hide_cursor(currcons);
+
#ifdef CONFIG_SELECTION
/* clear the selection as soon as any characters are to be written
out on the console holding the selection. */
@@ -854,18 +975,22 @@
* P.S. I hate 8 spaces per tab! Use Emacs!
*/
- if (!decim) {
+ /* Only use this for the foreground console,
+ where we really draw the chars */
+
+ if (!decim && currcons == fg_console) {
char *p = buf;
ushort count = 1;
ushort nextx = x + 1;
ushort cols = video_num_columns;
- *p++ = c;
+ *p++ = translate[c];
+ *pos++ = translate[c] | (attr << 8);
if (nextx == cols) {
sw->con_putc(&vc_cons[currcons],
- *buf, y, x, reverse ? DM_INVERSE
- : DM_COPY);
+ *buf, y, x);
+ pos--;
need_wrap = decawm;
continue;
}
@@ -876,7 +1001,8 @@
(c=get_tty_queue(&tty->write_q)) >= 0 &&
translate[c])
{
- *p++ = c;
+ *p++ = translate[c];
+ *pos++ = translate[c] | (attr << 8);
++count;
++nextx;
if (nextx == cols || count == sizeof (buf))
@@ -884,9 +1010,9 @@
}
sw->con_putcs(&vc_cons[currcons],
- buf, count, y, x, reverse ? DM_INVERSE
- : DM_COPY);
+ buf, count, y, x);
if (nextx == cols) {
+ pos--;
x = cols-1;
need_wrap = decawm;
continue;
@@ -907,17 +1033,19 @@
* TODO: build VT100 charset and enable translation.
*/
- /*c = translate[c];*/
+ c = translate[c];
/* Arno:
* 680x0: ignore attributes for now, just
* print character.
*/
- sw->con_putc(&vc_cons[currcons],c,y,x,
- reverse ? DM_INVERSE : DM_COPY);
+ *pos = c | (attr << 8);
+ if (currcons == fg_console)
+ sw->con_putc(&vc_cons[currcons],c,y,x);
if (x == video_num_columns - 1)
need_wrap = decawm;
else {
+ pos++;
x++;
}
continue;
@@ -935,11 +1063,13 @@
bs(currcons);
continue;
case 9:
+ pos -= x;
while (x < video_num_columns - 1) {
x++;
if (tab_stop[x >> 5] & (1 << (x & 31)))
break;
}
+ pos += x;
continue;
case 10: case 11: case 12:
lf(currcons);
@@ -1242,6 +1372,10 @@
if (!printable || currcons<0 || currcons>=NR_CONSOLES)
return;
+ /* undraw cursor first */
+ if (currcons == fg_console)
+ hide_cursor(currcons);
+
/* Contrived structure to try and emulate original need_wrap behaviour
* Problems caused when we have need_wrap set on '\n' character */
@@ -1249,8 +1383,10 @@
if (c == 10 || c == 13 || need_wrap) {
if ((count = b - start - 1) > 0) {
sw->con_putcs(&vc_cons[currcons], start, count ,
- y, x, DM_COPY);
+ y, x);
x += count;
+ if (need_wrap)
+ x--;
}
if (c != 13)
@@ -1264,16 +1400,18 @@
start = b-1; myx = x;
}
+ *pos = c | (attr << 8);
if (myx == video_num_columns - 1) {
need_wrap = 1;
continue;
}
+ pos++;
myx++;
}
if ((count = b - start -1) > 0) {
sw->con_putcs(&vc_cons[currcons], start, count ,
- y, x, DM_COPY);
+ y, x);
x += count;
if (x == video_num_columns)
{
@@ -1301,14 +1439,6 @@
char *display_desc = "????";
unsigned int currcons = 0;
-/*
- * Arno:
- * We really should move this to sw->con_init or some other platform
- * specific init code instead of hard-coding this...
- */
- display_desc="ECS";
- can_do_color=1;
-
sw=conswitchp;
timer_table[BLANK_TIMER].fn = blank_screen;
timer_table[BLANK_TIMER].expires = 0;
@@ -1316,17 +1446,7 @@
timer_table[BLANK_TIMER].expires = jiffies+blankinterval;
timer_active |= 1<<BLANK_TIMER;
}
- kmem_start = sw->con_init(&vc_cons[currcons], kmem_start);
-#if 0
-/*
- * Arno:
- * Strange things happen when more than 1 console is inited...
- *
- * TODO: extend low-level code for multi-console support.
- * Question: how are we going to do VC's? Save/restore bitplanes/copperlists
- * etc.? Can get memory expensive with 4 bitplane screens (in the future..)
- */
for (currcons = 0; currcons<NR_CONSOLES; currcons++) {
vcmode = KD_TEXT;
vtmode.mode = VT_AUTO;
@@ -1337,22 +1457,20 @@
vtpid = -1;
vtnewvt = -1;
clr_kbd(kbdraw);
+ sw = conswitchp;
+ can_do_color = 1;
+ kmem_start = sw->con_init(&vc_cons[currcons], kmem_start, &display_desc);
+ video_size_row = video_num_columns * 2;
+ pos = video_mem_start = (unsigned short *) kmem_start;
+ kmem_start += video_num_columns * video_num_lines * 2;
def_color = 0x07; /* white */
ulcolor = 0x0f; /* bold white */
halfcolor = 0x08; /* grey */
- reset_terminal(currcons, currcons);
-
-
+ reset_terminal(currcons, 1);
}
-#endif
-
+ vcmode = KD_TEXT;
currcons = fg_console = 0;
- def_color = 0x07; /* white */
- ulcolor = 0x0f; /* bold white */
- halfcolor = 0x08; /* grey */
- reset_terminal(currcons, currcons);
-
gotoxy(currcons,0,0);
save_cur(currcons);
gotoxy(currcons,0,0);
@@ -1365,7 +1483,7 @@
register_console(console_print);
printk("Console: %s %s %ldx%ld, %d virtual consoles\n",
- can_do_color?"colour":"mono",
+ can_do_color ? "colour":"mono",
display_desc,
video_num_columns,video_num_lines,
NR_CONSOLES);
@@ -1400,54 +1518,87 @@
timer_active |= 1<<BLANK_TIMER;
}
console_blanked = 0;
- (vc_cons[fg_console].vc_sw)->con_blank (0);
+ if ((vc_cons[fg_console].vc_sw)->con_blank (0))
+ /* Low-level driver cannot restore -> do it ourselves */
+ update_screen( fg_console );
+ set_cursor (fg_console);
}
void update_screen(int new_console)
{
+ int currcons = fg_console;
+ int xx, yy, startx, attr_save;
+ char buf[256], *bufp;
+ unsigned short *p;
static int lock = 0;
- if (new_console == fg_console || lock)
- return;
+ if (/* new_console == fg_console || */ lock)
return;
lock = 1;
- fg_console = new_console;
kbdsave(new_console);
-#if 0
- get_scrmem(fg_console);
- set_scrmem(fg_console);
- set_origin(fg_console);
- set_cursor(new_console);
+ sw->con_cursor (&vc_cons[currcons], CM_ERASE);
+ sw->con_switch (&vc_cons[new_console]);
+ currcons = fg_console = new_console;
+ /* Update the screen contents */
+ p = video_mem_start;
+ attr_save = attr;
+ for (yy = 0; yy < video_num_lines; yy++)
+ {
+ bufp = buf;
+ for (startx = xx = 0; xx < video_num_columns; xx++)
+ {
+ if (attr != (*p >> 8) & 0xff)
+ {
+ if (bufp > buf)
+ sw->con_putcs (&vc_cons[currcons], buf, bufp - buf,
+ yy, startx);
+ startx = xx;
+ bufp = buf;
+ attr = (*p >> 8) & 0xff;
+ }
+ *bufp++ = *p++;
+ if (bufp == buf + sizeof (buf))
+ {
+ sw->con_putcs (&vc_cons[currcons], buf, bufp - buf,
+ yy, startx);
+ startx = xx + 1;
+ bufp = buf;
+ }
+ }
+ if (bufp > buf)
+ sw->con_putcs (&vc_cons[currcons], buf, bufp - buf,
+ yy, startx);
+ }
+ set_cursor (currcons);
+ attr = attr_save;
set_leds();
compute_shiftstate();
-#endif
lock = 0;
}
int do_screendump(int arg)
{
-#if 0
char *sptr, *buf = (char *)arg;
int currcons, l;
if (!suser())
return -EPERM;
- l = verify_area(VERIFY_WRITE, buf,2+video_num_columns*video_num_lines);
+ l = verify_area(VERIFY_READ, buf,2);
if (l)
return l;
currcons = get_fs_byte(buf+1);
if ((currcons<0) || (currcons>NR_CONSOLES))
return -EIO;
+ currcons = (currcons ? currcons-1 : fg_console);
+ l = verify_area(VERIFY_WRITE, buf,2+video_num_columns*video_num_lines);
+ if (l)
+ return l;
put_fs_byte((char)(video_num_lines),buf++);
put_fs_byte((char)(video_num_columns),buf++);
- currcons = (currcons ? currcons-1 : fg_console);
- sptr = (char *) origin;
+ sptr = (char *) video_mem_start;
for (l=video_num_lines*video_num_columns; l>0 ; l--, sptr++)
put_fs_byte(*sptr++,buf++);
return(0);
-#else
- return -EOPNOTSUPP;
-#endif
}
/*
@@ -1468,24 +1619,45 @@
}
#ifdef CONFIG_SELECTION
-/* correction factor for when screen is hardware-scrolled */
-#define hwscroll_offset (currcons == fg_console ? ((__real_origin - __origin) << 1) : 0)
/* set reverse video on characters s-e of console with selection. */
static void highlight(const int currcons, const int s, const int e)
{
- unsigned char *p, *p1, *p2;
+ int xpos, ypos, k, start, end;
+ int oldattr, chattr;
+ unsigned short *p;
- p1 = (unsigned char *)origin - hwscroll_offset + s + 1;
- p2 = (unsigned char *)origin - hwscroll_offset + e + 1;
- if (p1 > p2)
+ if (s < e)
{
- p = p1;
- p1 = p2;
- p2 = p;
+ start = s >> 1;
+ end = e >> 1;
}
- for (p = p1; p <= p2; p += 2)
- *p = (*p & 0x88) | ((*p << 4) & 0x70) | ((*p >> 4) & 0x07);
+ else
+ {
+ start = e >> 1;
+ end = s >> 1;
+ }
+ oldattr = attr;
+
+ for (k = start; k <= end; k++)
+ {
+ ypos = k / video_num_columns;
+ xpos = k - (ypos * video_num_columns);
+ p = video_mem_start + k;
+ chattr = (*p >> 8) & 0xff;
+
+ if (can_do_color)
+ attr = ((chattr << 4) & 0x70) | ((chattr >> 4) & 0x07);
+ else
+ attr = chattr | 8;
+
+ /* invert the character on screen */
+ sw->con_putc(&vc_cons[currcons], *p & 0xff, ypos, xpos);
+ /* dunno if this might break with VCs - directly modifying the VC buffers */
+ /* write the (inverted) character into the VC buffer also */
+ *p = ((*p & 0xff) | (attr << 8));
+ }
+ attr = oldattr;
}
/* is c in range [a-zA-Z0-9_]? */
@@ -1494,6 +1666,7 @@
/* does screen address p correspond to character at LH/RH edge of screen? */
static inline int atedge(const int p)
{
+ int currcons = fg_console;
return (!(p % video_size_row) || !((p + 2) % video_size_row));
}
@@ -1511,7 +1684,12 @@
int sel_mode, new_sel_start, new_sel_end, spc;
char *bp, *obp, *spos;
int i, ps, pe;
- char *off = (char *)origin - hwscroll_offset;
+
+ /*
+ off is video_mem_start + 1 because the lower byte of a short in
+ the buffer contains the character
+ */
+ char *off = (char *)video_mem_start + 1;
unblank_screen();
args = (unsigned short *)(arg + 1);
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/char/lp.c linux-0.9pl4/drivers/char/lp.c
--- linux-0.9pl3/drivers/char/lp.c Sun Aug 14 10:30:39 1994
+++ linux-0.9pl4/drivers/char/lp.c Thu Nov 24 21:01:35 1994
@@ -138,7 +138,7 @@
static int lp_write_interrupt(struct inode * inode, struct file * file, char * buf, int count)
#endif
{
- static unsigned long total_bytes_written = 0;
+ unsigned long total_bytes_written = 0;
do {
bytes_written = 0;
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/char/mem.c linux-0.9pl4/drivers/char/mem.c
--- linux-0.9pl3/drivers/char/mem.c Tue Sep 27 22:24:36 1994
+++ linux-0.9pl4/drivers/char/mem.c Sun Oct 23 15:34:29 1994
@@ -94,12 +94,13 @@
{
struct vm_area_struct * mpnt;
- if (off & 0xfff || off + len < off)
+ if ((off & 0xfff) || off + len < off)
return -ENXIO;
#ifdef __i386__
if (x86 > 3 && off >= high_memory)
prot |= PAGE_PCD;
#endif
+
if (remap_page_range(addr, off, len, prot))
return -EAGAIN;
/* try to create a dummy vmm-structure so that the rest of the kernel knows we are here */
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/char/serial.c linux-0.9pl4/drivers/char/serial.c
--- linux-0.9pl3/drivers/char/serial.c Mon Sep 19 21:39:39 1994
+++ linux-0.9pl4/drivers/char/serial.c Mon Nov 21 18:09:04 1994
@@ -215,7 +215,7 @@
save_flags(flags); cli();
#ifdef SERIAL_DEBUG_OPEN
- printk("starting up ttyS%d ...", info->line);
+ printk("starting up ttyS%d\n", info->line);
#endif
info->sw->init( info );
@@ -247,7 +247,7 @@
return;
#ifdef SERIAL_DEBUG_OPEN
- printk("Shutting down serial port %d ....", info->line);
+ printk("Shutting down serial port %d\n", info->line);
#endif
save_flags(flags); cli(); /* Disable interrupts */
@@ -873,7 +873,7 @@
info->pgrp = current->pgrp;
#ifdef SERIAL_DEBUG_OPEN
- printk("rs_open ttyS%d successfull...", info->line);
+ printk("rs_open ttyS%d successfull\n", info->line);
#endif
return 0;
}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/char/tty_io.c linux-0.9pl4/drivers/char/tty_io.c
--- linux-0.9pl3/drivers/char/tty_io.c Mon Sep 19 21:29:37 1994
+++ linux-0.9pl4/drivers/char/tty_io.c Thu Oct 20 22:54:22 1994
@@ -778,7 +778,9 @@
}
if (tty->char_error == TTY_OVERRUN) {
tty->char_error = 0;
+#if 0 /* XXX */
printk("tty%d: input overrun\n", tty->line);
+#endif
continue;
}
/* Must be a parity or frame error */
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/net/slip.c linux-0.9pl4/drivers/net/slip.c
--- linux-0.9pl3/drivers/net/slip.c Sun Mar 13 08:47:58 1994
+++ linux-0.9pl4/drivers/net/slip.c Mon Oct 10 16:47:47 1994
@@ -1102,9 +1102,9 @@
DPRINTF((DBG_SLIP, "SLIP: ioctl(%d, 0x%X, 0x%X)\n", tty->line, cmd, arg));
switch(cmd) {
case SIOCGIFNAME:
- err=verify_area(VERIFY_WRITE, arg, 16);
+ err=verify_area(VERIFY_WRITE, arg, strlen(sl->dev->name) + 1);
if(err)
- return -err;
+ return err;
memcpy_tofs(arg, sl->dev->name, strlen(sl->dev->name) + 1);
return(0);
case SIOCGIFENCAP:
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/scsi/Makefile linux-0.9pl4/drivers/scsi/Makefile
--- linux-0.9pl3/drivers/scsi/Makefile Sun Aug 14 10:30:46 1994
+++ linux-0.9pl4/drivers/scsi/Makefile Mon Nov 7 22:25:08 1994
@@ -82,8 +82,8 @@
endif
ifdef CONFIG_ATARI_SCSI
-SCSI_OBJS := $(SCSI_OBJS) atari_sc.o
-SCSI_SRCS := $(SCSI_SRCS) atari_sc.c
+SCSI_OBJS := $(SCSI_OBJS) atari_scsi.o
+SCSI_SRCS := $(SCSI_SRCS) atari_scsi.c
endif
scsi.a: $(SCSI_OBJS)
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/scsi/atari_NCR5380.c linux-0.9pl4/drivers/scsi/atari_NCR5380.c
--- linux-0.9pl3/drivers/scsi/atari_NCR5380.c Tue Sep 27 22:22:09 1994
+++ linux-0.9pl4/drivers/scsi/atari_NCR5380.c Thu Nov 24 21:09:40 1994
@@ -59,7 +59,10 @@
/*
- * $Log: NCR5380.c,v $
+ * $Log: atari_NCR5380.c,v $
+ * Revision 1.1 1994/11/08 03:25:43 hamish
+ * Initial revision
+ *
* Revision 1.5 1994/01/19 09:14:57 drew
* Fixed udelay() hack that was being used on DATAOUT phases
* instead of a propper wait for the final handshake.
@@ -837,6 +840,7 @@
NCR5380_all_init();
hostdata->id_mask = 1 << instance->this_id;
+ hostdata->id_higher_mask = 0;
for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
if (i > hostdata->id_mask)
hostdata->id_higher_mask |= i;
@@ -1003,7 +1007,7 @@
*/
for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *)
- tmp->host_scribble)
+ tmp->host_scribble) {
/* When we find one, remove it from the issue queue. */
if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) {
@@ -1044,12 +1048,15 @@
hostdata->issue_queue;
hostdata->issue_queue = tmp;
sti();
+ if (hostdata->connected)
+ break;
#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES))
printk("scsi%d : main(): select() failed, returned to issue_queue\n",
instance->host_no);
#endif
}
} /* if target/lun is not busy */
+ }
} /* if (!hostdata->connected) */
if (hostdata->connected
@@ -1373,6 +1380,11 @@
* data bus during SELECTION.
*/
+ cli();
+ if (hostdata->connected) {
+ sti();
+ return -1;
+ }
NCR5380_write(TARGET_COMMAND_REG, 0);
/* Start arbitration */
@@ -1382,6 +1394,7 @@
/* Wait for arbitration logic to complete */
while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS));
+ sti();
#if (NDEBUG & NDEBUG_ARBITRATION)
printk("scsi%d : arbitration complete\n", instance->host_no);
/* Avoid GCC 2.4.5 asm needs to many reloads error */
@@ -1400,7 +1413,8 @@
/* Check for lost arbitration */
if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
(NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
- (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
+ (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ hostdata->connected) {
NCR5380_write(MODE_REG, MR_BASE);
#if (NDEBUG & NDEBUG_ARBITRATION)
printk("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n",
@@ -1428,6 +1442,12 @@
udelay(2);
+ if (hostdata->connected) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return -1;
+ }
+
#if (NDEBUG & NDEBUG_ARBITRATION)
printk("scsi%d : won arbitration\n", instance->host_no);
#endif
@@ -1453,6 +1473,12 @@
* Reselect interrupts must be turned off prior to the dropping of BSY,
* otherwise we will trigger an interrupt.
*/
+
+ if (hostdata->connected) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ return -1;
+ }
+
NCR5380_write(SELECT_ENABLE_REG, 0);
/* Reset BSY */
@@ -1764,9 +1790,6 @@
instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" :
"writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d);
#endif
- hostdata->dma_len = (p & SR_IO) ?
- NCR5380_dma_read_setup(instance, d, c) :
- NCR5380_dma_write_setup(instance, d, c);
#endif
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
@@ -1798,6 +1821,13 @@
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
NCR5380_write(START_DMA_SEND_REG, 0);
}
+#if defined(REAL_DMA) || defined(REAL_DMA_POLL)
+ cli();
+ hostdata->dma_len = (p & SR_IO) ?
+ NCR5380_dma_read_setup(instance, d, c) :
+ NCR5380_dma_write_setup(instance, d, c);
+ sti();
+#endif
#if defined(REAL_DMA_POLL)
do {
@@ -2084,19 +2114,13 @@
/* ++roman: I suggest, this should be
* #if def(REAL_DMA) || def(PSEUDO_DMA) || ...
* instead of leaving REAL_DMA out.
- *
- * GK: this does not work on FALCON:
- * #if def(REAL_DMA) || def(PSEUDO_DMA) || ...
- * ^^^^^^^^^^^^^^^^
- * results in timeout during partition check --> timeout in abort -->
- * timeout in reset --> kernel panic
*/
CHECK_ICNT("starting transf in inform_transf");
-#if /*defined(REAL_DMA) ||*/ defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
+#if defined(REAL_DMA) || defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
#ifdef NCR5380_dma_xfer_len
if (!scsi_devices[cmd->index].borken &&
- (transfersize = NCR5380_dma_xfer_len(instance, cmd)) > 7) {
+ (transfersize = NCR5380_dma_xfer_len(instance, cmd)) > 31) {
#else
if (!scsi_devices[cmd->index].borken &&
(transfersize = cmd->transfersize) &&
@@ -2144,6 +2168,7 @@
*/
len = 1;
data = &tmp;
+ NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */
NCR5380_transfer_pio(instance, &phase, &len, &data);
cmd->SCp.Message = tmp;
@@ -2165,6 +2190,8 @@
printk("scsi%d : target %d lun %d linked command complete.\n",
instance->host_no, cmd->target, cmd->lun);
#endif
+ /* Enable reselect interupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
/*
* Sanity check : A linked command should only terminate with
* one of these messages if there are more linked commands
@@ -2200,6 +2227,8 @@
instance->host_no, cmd->target, cmd->lun);
#endif
hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+ /* Enable reselect interupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
/* ++roman: For Falcon SCSI, release the lock an on the
* ST-DMA here if no other commands are waiting on the
@@ -2282,6 +2311,8 @@
!hostdata->connected);
return;
case MESSAGE_REJECT:
+ /* Enable reselect interupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
switch (hostdata->last_message) {
case HEAD_OF_QUEUE_TAG:
case ORDERED_QUEUE_TAG:
@@ -2293,8 +2324,8 @@
break;
}
case DISCONNECT:
- scsi_devices[cmd->index].disconnect = 1;
cli();
+ scsi_devices[cmd->index].disconnect = 1;
cmd->host_scribble = (unsigned char *)
hostdata->disconnected_queue;
hostdata->connected = NULL;
@@ -2324,8 +2355,12 @@
*/
case SAVE_POINTERS:
case RESTORE_POINTERS:
+ /* Enable reselect interupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
break;
default:
+ /* Enable reselect interupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
/*
* XXX rejected messages should be handled in the pio data transfer phase,
* since ATN should be raised before ACK goes false when we reject a message
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/scsi/atari_sc.c linux-0.9pl4/drivers/scsi/atari_sc.c
--- linux-0.9pl3/drivers/scsi/atari_sc.c Sun Aug 14 10:30:50 1994
+++ linux-0.9pl4/drivers/scsi/atari_sc.c Wed Dec 31 19:00:00 1969
@@ -1,763 +0,0 @@
-/*
- * atari_scsi.c -- Device dependant functions for the Atari generic SCSI port
- *
- * Copyright 1994 Roman Hodek
- * EMail: rnhodek@cip.informatik.uni-erlangen.de (Internet)
- * or: Roman_Hodek@n.maus.de (MausNet, NO mail > 16 KB!)
- *
- * Loosely based on the work of Robert De Vries' team and added:
- * - working real DMA
- * - Falcon support (untested yet!) ++bjoern fixed and now it works
- * - lots of extensions and bug fixes.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file README.legal in the main directory of this archive
- * for more details.
- *
- */
-
-
-/**************************************************************************/
-/* */
-/* Notes for Falcon SCSI: */
-/* ---------------------- */
-/* */
-/* Since the Falcon SCSI uses the ST-DMA chip, that is shared among */
-/* several device drivers, locking and unlocking the access to this */
-/* chip is required. But locking is not possible from an interrupt, */
-/* since it puts the process to sleep if the lock is not available. */
-/* This prevents "late" locking of the DMA chip, i.e. locking it just */
-/* before using it, since in case of disconnection-reconnection */
-/* commands, the DMA is started from the reselection interrupt. */
-/* */
-/* Two possible schemes for ST-DMA-locking would be: */
-/* 1) The lock is taken for each command separately and disconnecting */
-/* is forbidden (i.e. can_queue = 1). */
-/* 2) The DMA chip is locked when the first command comes in and */
-/* released when the last command is finished and all queues are */
-/* empty. */
-/* The first alternative would result in bad performance, since the */
-/* interleaving of commands would not be used. The second is unfair to */
-/* other drivers using the ST-DMA, because the queues will seldom be */
-/* totally empty if there is a lot of disk traffic. */
-/* */
-/* For this reasons I decided to employ a more elaborate scheme: */
-/* - First, we give up the lock everytime we can (for fairness), this */
-/* means every time a command finishes and there are no other commands */
-/* on the disconnected queue. */
-/* - If there are others waiting to lock the DMA chip, we stop */
-/* issueing commands, i.e. moving them onto the issue queue. */
-/* Because of that, the disconnected queue will run empty in a */
-/* while. Instead we go to sleep on a 'fairness_queue'. */
-/* - If the lock is released, all processes waiting on the fairness */
-/* queue will be woken. The first of them trys to re-lock the DMA, */
-/* the others wait for the first to finish this task. After that, */
-/* they can all run on and do their commands... */
-/* This sounds complicated (and it is it :-(), but it seems to be a */
-/* good compromise between fairness and performance: As long as noone */
-/* else wants to work with the ST-DMA chip, SCSI can go along as */
-/* usual. If now someone else comes, this behaviour is changed to a */
-/* "fairness mode": just already initiated commands are finished and */
-/* then the lock is released. The other one waiting will probably win */
-/* the race for locking the DMA, since it was waiting for longer. And */
-/* after it has finished, SCSI can go ahead again. Finally: I hope I */
-/* have not produced any deadlock possibilites! */
-/* */
-/**************************************************************************/
-
-
-
-#include <linux/config.h>
-
-#ifdef CONFIG_ATARI_SCSI
-
-/* #define NDEBUG (NDEBUG_DMA) */
-
-#define AUTOSENSE
-/* For the Atari version, use only polled IO or REAL_DMA */
-#define REAL_DMA
-
-#if I_HAVE_OVERRUNS == 1 || I_HAVE_OVERRUNS == 2
-#define READ_OVERRUNS
-#endif
-
-#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/interrupt.h>
-#include <linux/bootinfo.h>
-#include <linux/atarihw.h>
-#include <linux/atariints.h>
-#include "../block/blk.h"
-#include "scsi.h"
-#include "hosts.h"
-#include "atari_scsi.h"
-#include "NCR5380.h"
-#include "constants.h"
-#include <linux/atari_stdma.h>
-
-
-#define IS_A_TT() (boot_info.bi_atari.model == ATARI_TT)
-
-#define SCSI_DMA_WRITE_P(elt,val) \
- __asm__ __volatile__ ( "movepl %0,%1@(0)" : : "d" (val), \
- "a" (&tt_scsi_dma.elt) );
-
-#define SCSI_DMA_READ_P(elt) ({ \
- unsigned long __val; \
- __asm__ __volatile__ ( "movepl %1@(0),%0" \
- : "=d" (__val) : "a" (&tt_scsi_dma.elt)); \
- __val; })
-
-#define SCSI_DMA_SETADR(adr) \
- do { \
- unsigned long __adr = (adr); \
- st_dma.dma_lo = (unsigned char)__adr; \
- __adr >>= 8; \
- st_dma.dma_md = (unsigned char)__adr; \
- __adr >>= 8; \
- st_dma.dma_hi = (unsigned char)__adr; \
- } while(0)
-
-#define SCSI_DMA_GETADR() ({ \
- unsigned long __adr; \
- __adr = st_dma.dma_lo; \
- __asm__ __volatile__ ("nop"); \
- __adr |= (st_dma.dma_md & 0xff) << 8; \
- __adr |= (st_dma.dma_hi & 0xff) << 16; \
- __adr; \
-})
-
-
-
-/***************************** Prototypes *****************************/
-
-static void scsi_dma_buserr( struct intframe *fp, void *data);
-static void scsi_tt_intr( struct intframe *fp, void *data);
-static void scsi_falcon_intr( struct intframe *fp, void *data);
-static void atari_scsi_fetch_restbytes( void );
-static void falcon_release_lock_if_possible( struct NCR5380_hostdata *
- hostdata );
-static void falcon_get_lock( void );
-static long atari_scsi_dma_residual( struct Scsi_Host *instance );
-static unsigned long atari_dma_xfer_len( unsigned long wanted_len );
-static unsigned char atari_scsi_tt_reg_read( unsigned char reg );
-static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value
- );
-static unsigned char atari_scsi_falcon_reg_read( unsigned char reg );
-static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char
- value );
-
-/************************* End of Prototypes **************************/
-
-
-static struct Scsi_Host *atari_scsi_host = NULL;
-static unsigned char (*atari_scsi_reg_read)( unsigned char reg );
-static void (*atari_scsi_reg_write)( unsigned char reg, unsigned char value );
-
-#ifdef REAL_DMA
-static unsigned long atari_dma_residual, atari_dma_startaddr;
-static short atari_dma_active;
-#endif
-
-
-#if defined(REAL_DMA)
-
-static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
-
-{ int i;
- unsigned long addr = SCSI_DMA_READ_P( dma_addr_hi ), end_addr;
-
- if (dma_stat & 0x01) {
-
- /* A bus error happens when DMA-ing from the last page of a
- * physical memory chunk (DMA prefetch!), but that doesn't hurt.
- * Check for this case:
- */
-
- for( i = 0; i < boot_info.num_memory; ++i ) {
- end_addr = boot_info.memory[i].addr +
- boot_info.memory[i].size;
- if (end_addr <= addr && addr <= end_addr + 4)
- return( 1 );
- }
- }
- return( 0 );
-}
-
-
-static void scsi_dma_buserr (struct intframe *fp, void *data)
-
-{ unsigned char dma_stat = tt_scsi_dma.dma_ctrl;
-
- printk( "Bad SCSI DMA inmterrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n",
- SCSI_DMA_READ_P( dma_addr_hi ), dma_stat, SCSI_DMA_READ_P( dma_cnt_hi ) );
- if (dma_stat & 0x80) {
- if (!scsi_dma_is_ignored_buserr( dma_stat ))
- panic( "SCSI DMA bus error -- bad DMA programming!" );
- }
- else {
- /* Under normal circumstances we never should get to this point,
- * since both interrupts are triggered simultaneosly and the 5380
- * int has more priotity. When this irq is handled, that DMA
- * interrupt is cleared. So a warning message is printed here.
- */
- printk( "SCSI DMA intr ?? -- this shouldn't happen!\n" );
- }
-}
-
-#endif
-
-#undef LOST_INTR
-
-#ifdef LOST_INTR
-extern volatile unsigned long intr_count;
-unsigned long curr_intr_count;
-
-#define CHECK_ICNT(pos) do { \
- if (intr_count != curr_intr_count) { \
- printk( "INTR_COUNT changed before " pos \
- ": curr_cnt=%lu intr_cnt=%lu\n", \
- curr_intr_count, intr_count ); \
- } \
-} while( 0 )
-
-#else
-
-#define CHECK_ICNT(pos)
-
-#endif
-
-
-static void scsi_tt_intr (struct intframe *fp, void *data)
-
-{ int dma_stat;
- unsigned long flags;
-#ifdef LOST_INTR
- unsigned long prev_intr_count;
-
- prev_intr_count = curr_intr_count;
- curr_intr_count = intr_count;
-#endif
-
-#ifdef REAL_DMA
-
- dma_stat = tt_scsi_dma.dma_ctrl;
-
-#if (NDEBUG & NDEBUG_INTR)
- printk( "scsi%d: NCR5380 interupt, DMA status = %02x\n",
- atari_scsi_host->host_no, dma_stat & 0xff );
-#endif
-
- /* Look if it was the DMA that has interrupted: First possibility
- * is that a bus error occured...
- */
- if (dma_stat & 0x80) {
- if (!scsi_dma_is_ignored_buserr( dma_stat )) {
- printk( "SCSI DMA caused bus error near 0x%08lx\n",
- SCSI_DMA_READ_P( dma_addr_hi ));
- panic( "SCSI DMA bus error -- bad DMA programming!" );
- }
- }
-
- /* If the DMA is active but not finished, we have the the case
- * that some other 5380 interrupt occured within the DMA transfer.
- * This means we have residual bytes, if the desired end address
- * is not yet reached. Maybe we have to fetch some bytes from the
- * rest data register, too. The residual must be calculated from
- * the address pointer, not the counter register, because only the
- * addr reg counts bytes not yet written and pending in the rest
- * data reg!
- */
- if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
- atari_dma_residual =
- ((struct NCR5380_hostdata *)(atari_scsi_host->hostdata))->dma_len -
- (SCSI_DMA_READ_P( dma_addr_hi ) - atari_dma_startaddr);
-#if (NDEBUG & NDEBUG_DMA)
- printk( "SCSI DMA: There are %ld residual bytes.\n",
- atari_dma_residual );
-#endif
- atari_scsi_fetch_restbytes();
- tt_scsi_dma.dma_ctrl = 0;
- }
-
- /* If the DMA is finished, fetch the rest bytes and turn it off */
- if (dma_stat & 0x40) {
- atari_dma_residual = 0;
- atari_scsi_fetch_restbytes();
- tt_scsi_dma.dma_ctrl = 0;
- }
-
-#endif /* REAL_DMA */
-
- /* If we got this interrupt, we don't need the other one any more */
- tt_mfp.int_pn_b = (unsigned char)~0x80;
-
- CHECK_ICNT("calling NCR5380_intr");
-
- save_flags(flags);
- NCR5380_intr( 0 );
- restore_flags(flags);
-
-#ifdef LOST_INTR
- CHECK_ICNT("returning, after NCR5380_intr");
- curr_intr_count = prev_intr_count;
-#endif
-}
-
-
-static void scsi_falcon_intr (struct intframe *fp, void *data)
-
-{ int dma_stat;
- unsigned long flags;
-#ifdef LOST_INTR
- unsigned long prev_intr_count;
-
- prev_intr_count = curr_intr_count;
- curr_intr_count = intr_count;
-#endif
-
-#ifdef REAL_DMA
-
- /* Turn off DMA and select sector counter register before
- * accessing the status register (Atari recommendation!)
- */
- st_dma.dma_mode_status = 0x90;
- dma_stat = st_dma.dma_mode_status;
-
- /* Bit 0 indicates some error in the DMA process... don't know
- * what happened exactly (no further docu).
- */
- if (!(dma_stat & 0x01)) {
- /* DMA error */
- printk( "SCSI DMA error near 0x%08lx!\n", SCSI_DMA_GETADR() );
- }
-
- /* If the DMA was active, but now bit 1 is not clear, it is some
- * other 5380 interrupt that finishes the DMA transfer. We have to
- * calculate the number of residual bytes and give a warning if
- * bytes are stuck in the ST-DMA fifo (there's no way to reach them!)
- */
- if (atari_dma_active && (dma_stat & 0x02)) {
- unsigned long transferred;
-
- transferred = SCSI_DMA_GETADR() - atari_dma_startaddr;
- /* The ST-DMA address is incremented in 2-byte steps, but the
- * data are written only in 16-byte chunks. If the number of
- * transferred bytes is not divisible by 16, the remainder is
- * lost somewhere in outer space.
- */
- if (transferred & 15)
- printk( "SCSI DMA error: %ld bytes lost in ST-DMA fifo :-((\n",
- transferred & 15 );
-
- atari_dma_residual =
- ((struct NCR5380_hostdata *)(atari_scsi_host->hostdata))->dma_len -
- transferred;
-#if (NDEBUG & NDEBUG_DMA)
- printk( "SCSI DMA: There are %ld residual bytes.\n",
- atari_dma_residual );
-#endif
- }
- else
- atari_dma_residual = 0;
- atari_dma_active = 0;
-
-#endif /* REAL_DMA */
-
- CHECK_ICNT("calling NCR5380_intr");
-
- save_flags(flags);
- NCR5380_intr( 0 );
- restore_flags(flags);
-
-#ifdef LOST_INTR
- CHECK_ICNT("returning, after NCR5380_intr");
- curr_intr_count = prev_intr_count;
-#endif
-}
-
-
-static void atari_scsi_fetch_restbytes( void )
-
-{ int nr;
- char *src, *dst;
-
- /* fetch rest bytes in the DMA register */
- dst = (char *)SCSI_DMA_READ_P( dma_addr_hi );
- if ((nr = ((long)dst & 3))) {
- /* there are 'nr' bytes left for the last long address before the
- DMA pointer */
- dst = (char *)( (unsigned long)dst & ~3 );
-#if (NDEBUG & NDEBUG_DMA)
- printk( "SCSI DMA: there are %d rest bytes for phys addr 0x%08lx",
- nr, (long)dst );
-#endif
- dst = (char *)PTOV(dst); /* The content of the DMA pointer
- * is a physical address! */
-#if (NDEBUG & NDEBUG_DMA)
- printk( " = virt addr 0x%08lx\n", (long)dst );
-#endif
- for( src = (char *)&tt_scsi_dma.dma_restdata; nr > 0; --nr )
- *dst++ = *src++;
- }
-}
-
-
-static int falcon_got_lock = 0;
-static struct wait_queue *falcon_fairness_wait = NULL;
-static int falcon_trying_lock = 0;
-static struct wait_queue *falcon_try_wait = NULL;
-
-/* This function releases the lock on the DMA chip if there is no
- * connected command and the disconnected queue is empty. On
- * releasing, instances of falcon_get_lock are awoken, that put
- * themselves to sleep for fairness. They can now try to get the lock
- * again (but others waiting longer more probably will win).
- */
-
-static void
-falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
-
-{
- if (IS_A_TT()) return;
-
- if (falcon_got_lock &&
- !hostdata->disconnected_queue &&
- !hostdata->issue_queue &&
- !hostdata->connected) {
-
- unsigned long oldflags;
-
- save_flags(oldflags);
- cli();
-
- falcon_got_lock = 0;
- stdma_release();
- wake_up( &falcon_fairness_wait );
-
- restore_flags(oldflags);
- }
-}
-
-/* This function manages the locking of the ST-DMA.
- * If the DMA isn't locked already for SCSI, it trys to lock it by
- * calling stdma_lock(). But if the DMA is locked by the SCSI code and
- * there are other drivers waiting for the chip, we do not issue the
- * command immediatly but wait on 'falcon_fairness_queue'. We will be
- * waked up when the DMA is unlocked by some SCSI interrupt. After that
- * we try to get the lock again.
- * But we must be prepared that more then one instance of
- * falcon_get_lock() is waiting on the fairness queue. They should not
- * try all at once to call stdma_lock(), one is enough! For that, the
- * first one sets 'falcon_trying_lock', others that see that variable
- * set wait on the queue 'falcon_try_wait'.
- * Complicated, complicated.... Sigh...
- */
-
-static void falcon_get_lock( void )
-
-{
- unsigned long oldflags;
-
- if (IS_A_TT()) return;
-
- save_flags(oldflags);
- cli();
-
- while( falcon_got_lock && stdma_others_waiting() )
- sleep_on( &falcon_fairness_wait );
-
- if (!falcon_got_lock) {
- if (!falcon_trying_lock) {
- falcon_trying_lock = 1;
- stdma_lock( scsi_falcon_intr, 0 );
- falcon_got_lock = 1;
- falcon_trying_lock = 0;
- wake_up( &falcon_try_wait );
- }
- else {
- sleep_on( &falcon_try_wait );
- }
- }
-
- restore_flags(oldflags);
-}
-
-
-/* This is the wrapper function for NCR5380_queue_command(). It just
- * trys to get the lock on the ST-DMA (see above) and then calls the
- * original function.
- */
-
-int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
-
-{
- falcon_get_lock();
- return( NCR5380_queue_command( cmd, done ) );
-}
-
-
-
-int atari_scsi_detect (int hostno)
-
-{ static int called = 0;
- struct Scsi_Host *instance;
-
- if (boot_info.machtype != MACH_ATARI || called)
- return( 0 );
-
- atari_scsi_reg_read = IS_A_TT() ? atari_scsi_tt_reg_read :
- atari_scsi_falcon_reg_read;
- atari_scsi_reg_write = IS_A_TT() ? atari_scsi_tt_reg_write :
- atari_scsi_falcon_reg_write;
-
- instance = scsi_register (hostno, sizeof (struct NCR5380_hostdata));
- atari_scsi_host = instance;
-
- NCR5380_init (instance);
- instance->irq = 0; /* not needed, but tested in NCR5380.c */
-
- if (IS_A_TT()) {
-
- add_isr( IRQ_TT_MFP_SCSI, scsi_tt_intr, 0, NULL);
- tt_mfp.active_edge |= 0x80; /* SCSI int on L->H */
- tt_mfp.int_en_a |= 0x80; /* enabled */
- tt_mfp.int_mk_a |= 0x80; /* not masked */
-#ifdef REAL_DMA
- /* On the TT, we got a second interrupt for DMA ready and DMA buserror.
- * Since on DMA ready we get a "normal" interrupt, too, the service
- * routine for the second int just checks for buserrs.
- */
- add_isr( IRQ_TT_MFP_SCSIDMA, scsi_dma_buserr, 0, NULL);
- tt_mfp.active_edge &= ~0x20; /* DMA int on H->L */
- tt_mfp.int_en_b |= 0x80; /* enabled */
- tt_mfp.int_mk_b |= 0x80; /* not masked */
-
- tt_scsi_dma.dma_ctrl = 0;
- atari_dma_residual = 0;
-#endif /* REAL_DMA */
-
- }
- else { /* ! IS_A_TT */
-
- /* Nothing to do for the interrupt: the ST-DMA is initialized
- * already by atari_init_INTS()
- */
-
-#ifdef REAL_DMA
- atari_dma_residual = 0;
- atari_dma_active = 0;
-#endif
-
- /* Falcon's ST-DMA can work only in lower 16 MB, so
- * unchecked_isa_dma has to be set. But... the high level
- * codes allocates lots (!) of memory for buffers if this is
- * done. So the values for sg_tablesize and cmd_per_lun get
- * lowered a bit (you can leave this out if you have 16MB of
- * ST-Ram).
- */
- atari_scsi_host->unchecked_isa_dma =
- atari_scsi_host->hostt->unchecked_isa_dma = 1;
-#if I_HAVE_OVERRUNS == 3
- atari_scsi_host->sg_tablesize =
- atari_scsi_host->hostt->sg_tablesize = SG_NONE;
-#else
- atari_scsi_host->sg_tablesize =
- atari_scsi_host->hostt->sg_tablesize = 8;
-#endif
- atari_scsi_host->hostt->cmd_per_lun = 8;
- }
-
- printk( "scsi%d: options CAN_QUEUE=%d CMD_PER_LUN=%d SCATTERGATHER=%d",
- instance->host_no, instance->hostt->can_queue,
- instance->hostt->cmd_per_lun,
- instance->hostt->sg_tablesize );
- NCR5380_print_options (instance);
- printk ("\n");
-
- called = 1;
-
- return( 1 );
-}
-
-int atari_scsi_reset( Scsi_Cmnd *cmd )
-
-{ int rv;
-
- /* For doing the reset, SCSI interrupts must be disabled first,
- * since the 5380 raises its IRQ line while _RST is active and we
- * can't disable interrupts completely, since we need the timer.
- */
-
- if (IS_A_TT())
- tt_mfp.int_en_a &= ~0x80;
- else
- mfp.int_en_b &= ~0x80;
-
- rv = NCR5380_reset( cmd );
-
- /* Re-enable ints and abort a maybe active DMA transfer */
- if (IS_A_TT()) {
-#ifdef REAL_DMA
- tt_scsi_dma.dma_ctrl = 0;
-#endif /* REAL_DMA */
- tt_mfp.int_en_a |= 0x80;
- }
- else {
-#ifdef REAL_DMA
- st_dma.dma_mode_status = 0x90;
- atari_dma_active = 0;
-#endif /* REAL_DMA */
- mfp.int_en_b |= 0x80;
- }
-
- return( rv );
-}
-
-
-const char * atari_scsi_info( void )
-
-{ /* atari_scsi_detect() is verbose enough... */
- static const char string[] = "";
- return string;
-}
-
-
-#if defined(REAL_DMA) || defined(REAL_DMA_POLL) || defined(PSEUDO_DMA)
-
-unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data,
- unsigned long count, int dir )
-{
- unsigned long addr = VTOP( data ),
- cando = atari_dma_xfer_len( count );
-
-#if (NDEBUG & NDEBUG_DMA)
- printk ("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, cando = %ld, dir = %d\n",
- instance->host_no, data, addr, count, cando, dir);
-#endif
-
- atari_dma_startaddr = addr; /* Needed for calculating residual later. */
-
- if (dir)
- /* write: push any dirty cache out before sending it to the
- * peripheral. (Must be done before DMA setup, since at least the
- * ST-DMA begins to fill internal buffers right after setup.
- */
- cache_push( addr, cando );
- else
- /* read: invalidate any cache, may be altered after DMA without CPU
- * knowledge
- */
- cache_clear( addr, cando );
-
- if (cando == 0)
- printk( "SCSI warning: DMA programed for 0 bytes !\n" );
-
- if (IS_A_TT()) {
-
- tt_scsi_dma.dma_ctrl = dir;
- SCSI_DMA_WRITE_P( dma_addr_hi, addr );
- SCSI_DMA_WRITE_P( dma_cnt_hi, cando );
- tt_scsi_dma.dma_ctrl = dir | 2;
- }
- else { /* ! IS_A_TT */
-
- /* set address */
- SCSI_DMA_SETADR( addr );
-
- /* toggle direction bit to clear FIFO and set DMA direction */
- dir <<= 8;
- st_dma.dma_mode_status = 0x90 | dir;
- st_dma.dma_mode_status = 0x90 | (dir ^ 0x100);
- st_dma.dma_mode_status = 0x90 | dir;
- st_dma.fdc_acces_seccount = cando >> 9;
-
- st_dma.dma_mode_status = 0x10 | dir;
- /* need not restore value of dir, only boolean value is tested */
- atari_dma_active = 1;
- }
-
- return( cando );
-}
-
-
-static long atari_scsi_dma_residual( struct Scsi_Host *instance )
-
-{
- return( atari_dma_residual );
-}
-
-/* This function calculates the number of bytes that can be transferred
- * via DMA. On the TT, this is arbitrary, but on the Falcon we have to use
- * the ST-DMA chip. There are only multiples of 512 bytes possible and
- * max. 256*512 bytes :-( This means also, that defining READ_OVERRUNS is
- * not possible, since that would require to program the DMA for n*512 - 2
- * bytes.
- */
-
-static unsigned long atari_dma_xfer_len( unsigned long wanted_len )
-
-{
- unsigned long possible_len;
-
- if (IS_A_TT())
- /* TT SCSI DMA can transfer arbitrary #bytes */
- return( wanted_len );
-
- /* ST DMA chip is stupid -- only multiples of 512 bytes! (and max.
- * 255*512 bytes, but this should be enough)
- */
- possible_len =wanted_len & ~0x1ff;
- if (possible_len > 255*512)
- possible_len = 255*512;
-
-#if (NDEBUG & NDEBUG_DMA)
- if (possible_len != wanted_len)
- printk( "Sorry, must cut DMA transfer size to %ld bytes instead of %ld\n",
- possible_len, wanted_len );
-#endif
-
- return( possible_len );
-}
-
-
-#endif /* REAL_DMA || REAL_DMA_POLL || PSEUDO_DMA */
-
-
-/* NCR5380 register access functions
- *
- * There are seperate functions for TT and Falcon, because the access
- * methods are quite different. The calling macros NCR5380_read and
- * NCR5380_write call these functions via function pointers.
- */
-
-static unsigned char atari_scsi_tt_reg_read( unsigned char reg )
-
-{
- return( tt_scsi_regp[reg * 2] );
-}
-
-static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value )
-
-{
- tt_scsi_regp[reg * 2] = value;
-}
-
-static unsigned char atari_scsi_falcon_reg_read( unsigned char reg )
-
-{
- dma_wd.dma_mode_status= (u_short)(0x88 + reg);
- return( (u_char)dma_wd.fdc_acces_seccount );
-}
-
-static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value )
-
-{
- dma_wd.dma_mode_status = (u_short)(0x88 + reg);
- dma_wd.fdc_acces_seccount = (u_short)value;
-}
-
-
-#include "atari_NCR5380.c"
-
-#endif /* CONFIG_ATARI_*_SCSI */
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/scsi/atari_scsi.c linux-0.9pl4/drivers/scsi/atari_scsi.c
--- linux-0.9pl3/drivers/scsi/atari_scsi.c Wed Dec 31 19:00:00 1969
+++ linux-0.9pl4/drivers/scsi/atari_scsi.c Mon Nov 7 22:28:17 1994
@@ -0,0 +1,766 @@
+/*
+ * atari_scsi.c -- Device dependant functions for the Atari generic SCSI port
+ *
+ * Copyright 1994 Roman Hodek
+ * EMail: rnhodek@cip.informatik.uni-erlangen.de (Internet)
+ * or: Roman_Hodek@n.maus.de (MausNet, NO mail > 16 KB!)
+ *
+ * Loosely based on the work of Robert De Vries' team and added:
+ * - working real DMA
+ * - Falcon support (untested yet!) ++bjoern fixed and now it works
+ * - lots of extensions and bug fixes.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file README.legal in the main directory of this archive
+ * for more details.
+ *
+ */
+
+
+/**************************************************************************/
+/* */
+/* Notes for Falcon SCSI: */
+/* ---------------------- */
+/* */
+/* Since the Falcon SCSI uses the ST-DMA chip, that is shared among */
+/* several device drivers, locking and unlocking the access to this */
+/* chip is required. But locking is not possible from an interrupt, */
+/* since it puts the process to sleep if the lock is not available. */
+/* This prevents "late" locking of the DMA chip, i.e. locking it just */
+/* before using it, since in case of disconnection-reconnection */
+/* commands, the DMA is started from the reselection interrupt. */
+/* */
+/* Two possible schemes for ST-DMA-locking would be: */
+/* 1) The lock is taken for each command separately and disconnecting */
+/* is forbidden (i.e. can_queue = 1). */
+/* 2) The DMA chip is locked when the first command comes in and */
+/* released when the last command is finished and all queues are */
+/* empty. */
+/* The first alternative would result in bad performance, since the */
+/* interleaving of commands would not be used. The second is unfair to */
+/* other drivers using the ST-DMA, because the queues will seldom be */
+/* totally empty if there is a lot of disk traffic. */
+/* */
+/* For this reasons I decided to employ a more elaborate scheme: */
+/* - First, we give up the lock everytime we can (for fairness), this */
+/* means every time a command finishes and there are no other commands */
+/* on the disconnected queue. */
+/* - If there are others waiting to lock the DMA chip, we stop */
+/* issueing commands, i.e. moving them onto the issue queue. */
+/* Because of that, the disconnected queue will run empty in a */
+/* while. Instead we go to sleep on a 'fairness_queue'. */
+/* - If the lock is released, all processes waiting on the fairness */
+/* queue will be woken. The first of them trys to re-lock the DMA, */
+/* the others wait for the first to finish this task. After that, */
+/* they can all run on and do their commands... */
+/* This sounds complicated (and it is it :-(), but it seems to be a */
+/* good compromise between fairness and performance: As long as noone */
+/* else wants to work with the ST-DMA chip, SCSI can go along as */
+/* usual. If now someone else comes, this behaviour is changed to a */
+/* "fairness mode": just already initiated commands are finished and */
+/* then the lock is released. The other one waiting will probably win */
+/* the race for locking the DMA, since it was waiting for longer. And */
+/* after it has finished, SCSI can go ahead again. Finally: I hope I */
+/* have not produced any deadlock possibilites! */
+/* */
+/**************************************************************************/
+
+
+
+#include <linux/config.h>
+
+#ifdef CONFIG_ATARI_SCSI
+
+/* #define NDEBUG (NDEBUG_DMA) */
+
+#define AUTOSENSE
+/* For the Atari version, use only polled IO or REAL_DMA */
+#define REAL_DMA
+
+#if I_HAVE_OVERRUNS == 1 || I_HAVE_OVERRUNS == 2
+#define READ_OVERRUNS
+#endif
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/interrupt.h>
+#include <linux/bootinfo.h>
+#include <linux/delay.h>
+#include <linux/atarihw.h>
+#include <linux/atariints.h>
+#include "../block/blk.h"
+#include "scsi.h"
+#include "hosts.h"
+#include "atari_scsi.h"
+#include "NCR5380.h"
+#include "constants.h"
+#include <linux/atari_stdma.h>
+
+
+#define IS_A_TT() (boot_info.bi_atari.model == ATARI_TT)
+
+#define SCSI_DMA_WRITE_P(elt,val) \
+ __asm__ __volatile__ ( "movepl %0,%1@(0)" : : "d" (val), \
+ "a" (&tt_scsi_dma.elt) );
+
+#define SCSI_DMA_READ_P(elt) ({ \
+ unsigned long __val; \
+ __asm__ __volatile__ ( "movepl %1@(0),%0" \
+ : "=d" (__val) : "a" (&tt_scsi_dma.elt)); \
+ __val; })
+
+#define SCSI_DMA_SETADR(adr) \
+ do { \
+ unsigned long __adr = (adr); \
+ st_dma.dma_lo = (unsigned char)__adr; \
+ __adr >>= 8; \
+ st_dma.dma_md = (unsigned char)__adr; \
+ __adr >>= 8; \
+ st_dma.dma_hi = (unsigned char)__adr; \
+ } while(0)
+
+#define SCSI_DMA_GETADR() ({ \
+ unsigned long __adr; \
+ __adr = st_dma.dma_lo; \
+ __asm__ __volatile__ ("nop"); \
+ __adr |= (st_dma.dma_md & 0xff) << 8; \
+ __adr |= (st_dma.dma_hi & 0xff) << 16; \
+ __adr; \
+})
+
+
+
+/***************************** Prototypes *****************************/
+
+static void scsi_dma_buserr( struct intframe *fp, void *data);
+static void scsi_tt_intr( struct intframe *fp, void *data);
+static void scsi_falcon_intr( struct intframe *fp, void *data);
+static void atari_scsi_fetch_restbytes( void );
+static void falcon_release_lock_if_possible( struct NCR5380_hostdata *
+ hostdata );
+static void falcon_get_lock( void );
+static long atari_scsi_dma_residual( struct Scsi_Host *instance );
+static unsigned long atari_dma_xfer_len( unsigned long wanted_len );
+static unsigned char atari_scsi_tt_reg_read( unsigned char reg );
+static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value
+ );
+static unsigned char atari_scsi_falcon_reg_read( unsigned char reg );
+static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char
+ value );
+
+/************************* End of Prototypes **************************/
+
+
+static struct Scsi_Host *atari_scsi_host = NULL;
+static unsigned char (*atari_scsi_reg_read)( unsigned char reg );
+static void (*atari_scsi_reg_write)( unsigned char reg, unsigned char value );
+
+#ifdef REAL_DMA
+static unsigned long atari_dma_residual, atari_dma_startaddr;
+static short atari_dma_active;
+#endif
+
+
+#if defined(REAL_DMA)
+
+static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
+
+{ int i;
+ unsigned long addr = SCSI_DMA_READ_P( dma_addr_hi ), end_addr;
+
+ if (dma_stat & 0x01) {
+
+ /* A bus error happens when DMA-ing from the last page of a
+ * physical memory chunk (DMA prefetch!), but that doesn't hurt.
+ * Check for this case:
+ */
+
+ for( i = 0; i < boot_info.num_memory; ++i ) {
+ end_addr = boot_info.memory[i].addr +
+ boot_info.memory[i].size;
+ if (end_addr <= addr && addr <= end_addr + 4)
+ return( 1 );
+ }
+ }
+ return( 0 );
+}
+
+
+static void scsi_dma_buserr (struct intframe *fp, void *data)
+
+{ unsigned char dma_stat = tt_scsi_dma.dma_ctrl;
+
+ printk( "Bad SCSI DMA inmterrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n",
+ SCSI_DMA_READ_P( dma_addr_hi ), dma_stat, SCSI_DMA_READ_P( dma_cnt_hi ) );
+ if (dma_stat & 0x80) {
+ if (!scsi_dma_is_ignored_buserr( dma_stat ))
+ panic( "SCSI DMA bus error -- bad DMA programming!" );
+ }
+ else {
+ /* Under normal circumstances we never should get to this point,
+ * since both interrupts are triggered simultaneosly and the 5380
+ * int has more priotity. When this irq is handled, that DMA
+ * interrupt is cleared. So a warning message is printed here.
+ */
+ printk( "SCSI DMA intr ?? -- this shouldn't happen!\n" );
+ }
+}
+
+#endif
+
+#undef LOST_INTR
+
+#ifdef LOST_INTR
+extern volatile unsigned long intr_count;
+unsigned long curr_intr_count;
+
+#define CHECK_ICNT(pos) do { \
+ if (intr_count != curr_intr_count) { \
+ printk( "INTR_COUNT changed before " pos \
+ ": curr_cnt=%lu intr_cnt=%lu\n", \
+ curr_intr_count, intr_count ); \
+ } \
+} while( 0 )
+
+#else
+
+#define CHECK_ICNT(pos)
+
+#endif
+
+
+static void scsi_tt_intr (struct intframe *fp, void *data)
+
+{ int dma_stat;
+ unsigned long flags;
+#ifdef LOST_INTR
+ unsigned long prev_intr_count;
+
+ prev_intr_count = curr_intr_count;
+ curr_intr_count = intr_count;
+#endif
+
+#ifdef REAL_DMA
+
+ dma_stat = tt_scsi_dma.dma_ctrl;
+
+#if (NDEBUG & NDEBUG_INTR)
+ printk( "scsi%d: NCR5380 interupt, DMA status = %02x\n",
+ atari_scsi_host->host_no, dma_stat & 0xff );
+#endif
+
+ /* Look if it was the DMA that has interrupted: First possibility
+ * is that a bus error occured...
+ */
+ if (dma_stat & 0x80) {
+ if (!scsi_dma_is_ignored_buserr( dma_stat )) {
+ printk( "SCSI DMA caused bus error near 0x%08lx\n",
+ SCSI_DMA_READ_P( dma_addr_hi ));
+ panic( "SCSI DMA bus error -- bad DMA programming!" );
+ }
+ }
+
+ /* If the DMA is active but not finished, we have the the case
+ * that some other 5380 interrupt occured within the DMA transfer.
+ * This means we have residual bytes, if the desired end address
+ * is not yet reached. Maybe we have to fetch some bytes from the
+ * rest data register, too. The residual must be calculated from
+ * the address pointer, not the counter register, because only the
+ * addr reg counts bytes not yet written and pending in the rest
+ * data reg!
+ */
+ if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
+ atari_dma_residual =
+ ((struct NCR5380_hostdata *)(atari_scsi_host->hostdata))->dma_len -
+ (SCSI_DMA_READ_P( dma_addr_hi ) - atari_dma_startaddr);
+#if (NDEBUG & NDEBUG_DMA)
+ printk( "SCSI DMA: There are %ld residual bytes.\n",
+ atari_dma_residual );
+#endif
+ atari_scsi_fetch_restbytes();
+ tt_scsi_dma.dma_ctrl = 0;
+ }
+
+ /* If the DMA is finished, fetch the rest bytes and turn it off */
+ if (dma_stat & 0x40) {
+ atari_dma_residual = 0;
+ atari_scsi_fetch_restbytes();
+ tt_scsi_dma.dma_ctrl = 0;
+ }
+
+#endif /* REAL_DMA */
+
+ /* If we got this interrupt, we don't need the other one any more */
+ tt_mfp.int_pn_b = (unsigned char)~0x80;
+
+ CHECK_ICNT("calling NCR5380_intr");
+
+ save_flags(flags);
+ NCR5380_intr( 0 );
+ restore_flags(flags);
+
+#ifdef LOST_INTR
+ CHECK_ICNT("returning, after NCR5380_intr");
+ curr_intr_count = prev_intr_count;
+#endif
+}
+
+
+static void scsi_falcon_intr (struct intframe *fp, void *data)
+
+{ int dma_stat;
+ unsigned long flags;
+#ifdef LOST_INTR
+ unsigned long prev_intr_count;
+
+ prev_intr_count = curr_intr_count;
+ curr_intr_count = intr_count;
+#endif
+
+#ifdef REAL_DMA
+
+ /* Turn off DMA and select sector counter register before
+ * accessing the status register (Atari recommendation!)
+ */
+ st_dma.dma_mode_status = 0x90;
+ dma_stat = st_dma.dma_mode_status;
+
+ /* Bit 0 indicates some error in the DMA process... don't know
+ * what happened exactly (no further docu).
+ */
+ if (!(dma_stat & 0x01)) {
+ /* DMA error */
+ printk( "SCSI DMA error near 0x%08lx!\n", SCSI_DMA_GETADR() );
+ }
+
+ /* If the DMA was active, but now bit 1 is not clear, it is some
+ * other 5380 interrupt that finishes the DMA transfer. We have to
+ * calculate the number of residual bytes and give a warning if
+ * bytes are stuck in the ST-DMA fifo (there's no way to reach them!)
+ */
+ if (atari_dma_active && (dma_stat & 0x02)) {
+ unsigned long transferred;
+
+ transferred = SCSI_DMA_GETADR() - atari_dma_startaddr;
+ /* The ST-DMA address is incremented in 2-byte steps, but the
+ * data are written only in 16-byte chunks. If the number of
+ * transferred bytes is not divisible by 16, the remainder is
+ * lost somewhere in outer space.
+ */
+ if (transferred & 15)
+ printk( "SCSI DMA error: %ld bytes lost in ST-DMA fifo :-((\n",
+ transferred & 15 );
+
+ atari_dma_residual =
+ ((struct NCR5380_hostdata *)(atari_scsi_host->hostdata))->dma_len -
+ transferred;
+#if (NDEBUG & NDEBUG_DMA)
+ printk( "SCSI DMA: There are %ld residual bytes.\n",
+ atari_dma_residual );
+#endif
+ }
+ else
+ atari_dma_residual = 0;
+ atari_dma_active = 0;
+
+#endif /* REAL_DMA */
+
+ CHECK_ICNT("calling NCR5380_intr");
+
+ save_flags(flags);
+ NCR5380_intr( 0 );
+ restore_flags(flags);
+
+#ifdef LOST_INTR
+ CHECK_ICNT("returning, after NCR5380_intr");
+ curr_intr_count = prev_intr_count;
+#endif
+}
+
+
+static void atari_scsi_fetch_restbytes( void )
+
+{ int nr;
+ char *src, *dst;
+
+ /* fetch rest bytes in the DMA register */
+ dst = (char *)SCSI_DMA_READ_P( dma_addr_hi );
+ if ((nr = ((long)dst & 3))) {
+ /* there are 'nr' bytes left for the last long address before the
+ DMA pointer */
+ dst = (char *)( (unsigned long)dst & ~3 );
+#if (NDEBUG & NDEBUG_DMA)
+ printk( "SCSI DMA: there are %d rest bytes for phys addr 0x%08lx",
+ nr, (long)dst );
+#endif
+ dst = (char *)PTOV(dst); /* The content of the DMA pointer
+ * is a physical address! */
+#if (NDEBUG & NDEBUG_DMA)
+ printk( " = virt addr 0x%08lx\n", (long)dst );
+#endif
+ for( src = (char *)&tt_scsi_dma.dma_restdata; nr > 0; --nr )
+ *dst++ = *src++;
+ }
+}
+
+
+static int falcon_got_lock = 0;
+static struct wait_queue *falcon_fairness_wait = NULL;
+static int falcon_trying_lock = 0;
+static struct wait_queue *falcon_try_wait = NULL;
+
+/* This function releases the lock on the DMA chip if there is no
+ * connected command and the disconnected queue is empty. On
+ * releasing, instances of falcon_get_lock are awoken, that put
+ * themselves to sleep for fairness. They can now try to get the lock
+ * again (but others waiting longer more probably will win).
+ */
+
+static void
+falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
+
+{
+ if (IS_A_TT()) return;
+
+ if (falcon_got_lock &&
+ !hostdata->disconnected_queue &&
+ !hostdata->issue_queue &&
+ !hostdata->connected) {
+
+ unsigned long oldflags;
+
+ save_flags(oldflags);
+ cli();
+
+ falcon_got_lock = 0;
+ stdma_release();
+ wake_up( &falcon_fairness_wait );
+
+ restore_flags(oldflags);
+ }
+}
+
+/* This function manages the locking of the ST-DMA.
+ * If the DMA isn't locked already for SCSI, it trys to lock it by
+ * calling stdma_lock(). But if the DMA is locked by the SCSI code and
+ * there are other drivers waiting for the chip, we do not issue the
+ * command immediatly but wait on 'falcon_fairness_queue'. We will be
+ * waked up when the DMA is unlocked by some SCSI interrupt. After that
+ * we try to get the lock again.
+ * But we must be prepared that more then one instance of
+ * falcon_get_lock() is waiting on the fairness queue. They should not
+ * try all at once to call stdma_lock(), one is enough! For that, the
+ * first one sets 'falcon_trying_lock', others that see that variable
+ * set wait on the queue 'falcon_try_wait'.
+ * Complicated, complicated.... Sigh...
+ */
+
+static void falcon_get_lock( void )
+
+{
+ unsigned long oldflags;
+
+ if (IS_A_TT()) return;
+
+ save_flags(oldflags);
+ cli();
+
+ while( falcon_got_lock && stdma_others_waiting() )
+ sleep_on( &falcon_fairness_wait );
+
+ if (!falcon_got_lock) {
+ if (!falcon_trying_lock) {
+ falcon_trying_lock = 1;
+ stdma_lock( scsi_falcon_intr, 0 );
+ falcon_got_lock = 1;
+ falcon_trying_lock = 0;
+ wake_up( &falcon_try_wait );
+ }
+ else {
+ sleep_on( &falcon_try_wait );
+ }
+ }
+
+ restore_flags(oldflags);
+}
+
+
+/* This is the wrapper function for NCR5380_queue_command(). It just
+ * trys to get the lock on the ST-DMA (see above) and then calls the
+ * original function.
+ */
+
+int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+
+{
+ falcon_get_lock();
+ return( NCR5380_queue_command( cmd, done ) );
+}
+
+
+
+int atari_scsi_detect (int hostno)
+
+{ static int called = 0;
+ struct Scsi_Host *instance;
+
+ if (boot_info.machtype != MACH_ATARI || called)
+ return( 0 );
+
+ atari_scsi_reg_read = IS_A_TT() ? atari_scsi_tt_reg_read :
+ atari_scsi_falcon_reg_read;
+ atari_scsi_reg_write = IS_A_TT() ? atari_scsi_tt_reg_write :
+ atari_scsi_falcon_reg_write;
+
+ instance = scsi_register (hostno, sizeof (struct NCR5380_hostdata));
+ atari_scsi_host = instance;
+
+ NCR5380_init (instance);
+ instance->irq = 0; /* not needed, but tested in NCR5380.c */
+
+ if (IS_A_TT()) {
+
+ add_isr( IRQ_TT_MFP_SCSI, scsi_tt_intr, 0, NULL);
+ tt_mfp.active_edge |= 0x80; /* SCSI int on L->H */
+ tt_mfp.int_en_a |= 0x80; /* enabled */
+ tt_mfp.int_mk_a |= 0x80; /* not masked */
+#ifdef REAL_DMA
+ /* On the TT, we got a second interrupt for DMA ready and DMA buserror.
+ * Since on DMA ready we get a "normal" interrupt, too, the service
+ * routine for the second int just checks for buserrs.
+ */
+ add_isr( IRQ_TT_MFP_SCSIDMA, scsi_dma_buserr, 0, NULL);
+ tt_mfp.active_edge &= ~0x20; /* DMA int on H->L */
+ tt_mfp.int_en_b |= 0x80; /* enabled */
+ tt_mfp.int_mk_b |= 0x80; /* not masked */
+
+ tt_scsi_dma.dma_ctrl = 0;
+ atari_dma_residual = 0;
+#endif /* REAL_DMA */
+
+ }
+ else { /* ! IS_A_TT */
+
+ /* Nothing to do for the interrupt: the ST-DMA is initialized
+ * already by atari_init_INTS()
+ */
+
+#ifdef REAL_DMA
+ atari_dma_residual = 0;
+ atari_dma_active = 0;
+#endif
+
+ /* Falcon's ST-DMA can work only in lower 16 MB, so
+ * unchecked_isa_dma has to be set. But... the high level
+ * codes allocates lots (!) of memory for buffers if this is
+ * done. So the values for sg_tablesize and cmd_per_lun get
+ * lowered a bit (you can leave this out if you have 16MB of
+ * ST-Ram).
+ */
+ atari_scsi_host->unchecked_isa_dma =
+ atari_scsi_host->hostt->unchecked_isa_dma = 1;
+#if I_HAVE_OVERRUNS == 3
+ atari_scsi_host->sg_tablesize =
+ atari_scsi_host->hostt->sg_tablesize = SG_NONE;
+#else
+ atari_scsi_host->sg_tablesize =
+ atari_scsi_host->hostt->sg_tablesize = 8;
+#endif
+ atari_scsi_host->hostt->cmd_per_lun = 8;
+ }
+
+ printk( "scsi%d: options CAN_QUEUE=%d CMD_PER_LUN=%d SCATTERGATHER=%d",
+ instance->host_no, instance->hostt->can_queue,
+ instance->hostt->cmd_per_lun,
+ instance->hostt->sg_tablesize );
+ NCR5380_print_options (instance);
+ printk ("\n");
+
+ called = 1;
+
+ return( 1 );
+}
+
+int atari_scsi_reset( Scsi_Cmnd *cmd )
+
+{ int rv;
+
+ /* For doing the reset, SCSI interrupts must be disabled first,
+ * since the 5380 raises its IRQ line while _RST is active and we
+ * can't disable interrupts completely, since we need the timer.
+ */
+
+ if (IS_A_TT())
+ tt_mfp.int_en_a &= ~0x80;
+ else
+ mfp.int_en_b &= ~0x80;
+
+ rv = NCR5380_reset( cmd );
+
+ /* Re-enable ints and abort a maybe active DMA transfer */
+ if (IS_A_TT()) {
+#ifdef REAL_DMA
+ tt_scsi_dma.dma_ctrl = 0;
+#endif /* REAL_DMA */
+ tt_mfp.int_en_a |= 0x80;
+ }
+ else {
+#ifdef REAL_DMA
+ st_dma.dma_mode_status = 0x90;
+ atari_dma_active = 0;
+#endif /* REAL_DMA */
+ mfp.int_en_b |= 0x80;
+ }
+
+ return( rv );
+}
+
+
+const char * atari_scsi_info( void )
+
+{ /* atari_scsi_detect() is verbose enough... */
+ static const char string[] = "";
+ return string;
+}
+
+
+#if defined(REAL_DMA) || defined(REAL_DMA_POLL) || defined(PSEUDO_DMA)
+
+unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data,
+ unsigned long count, int dir )
+{
+ unsigned long addr = VTOP( data ),
+ cando = atari_dma_xfer_len( count );
+
+#if (NDEBUG & NDEBUG_DMA)
+ printk ("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, cando = %ld, dir = %d\n",
+ instance->host_no, data, addr, count, cando, dir);
+#endif
+
+ atari_dma_startaddr = addr; /* Needed for calculating residual later. */
+
+ if (dir)
+ /* write: push any dirty cache out before sending it to the
+ * peripheral. (Must be done before DMA setup, since at least the
+ * ST-DMA begins to fill internal buffers right after setup.
+ */
+ cache_push( addr, cando );
+ else
+ /* read: invalidate any cache, may be altered after DMA without CPU
+ * knowledge
+ */
+ cache_clear( addr, cando );
+
+ if (cando == 0)
+ printk( "SCSI warning: DMA programed for 0 bytes !\n" );
+
+ if (IS_A_TT()) {
+
+ tt_scsi_dma.dma_ctrl = dir;
+ SCSI_DMA_WRITE_P( dma_addr_hi, addr );
+ SCSI_DMA_WRITE_P( dma_cnt_hi, cando );
+ tt_scsi_dma.dma_ctrl = dir | 2;
+ }
+ else { /* ! IS_A_TT */
+
+ /* set address */
+ SCSI_DMA_SETADR( addr );
+
+ /* toggle direction bit to clear FIFO and set DMA direction */
+ dir <<= 8;
+ st_dma.dma_mode_status = 0x90 | dir;
+ st_dma.dma_mode_status = 0x90 | (dir ^ 0x100);
+ st_dma.dma_mode_status = 0x90 | dir;
+ udelay(40);
+ st_dma.fdc_acces_seccount = cando >> 9;
+ udelay(40);
+ st_dma.dma_mode_status = 0x10 | dir;
+ udelay(40);
+ /* need not restore value of dir, only boolean value is tested */
+ atari_dma_active = 1;
+ }
+
+ return( cando );
+}
+
+
+static long atari_scsi_dma_residual( struct Scsi_Host *instance )
+
+{
+ return( atari_dma_residual );
+}
+
+/* This function calculates the number of bytes that can be transferred
+ * via DMA. On the TT, this is arbitrary, but on the Falcon we have to use
+ * the ST-DMA chip. There are only multiples of 512 bytes possible and
+ * max. 256*512 bytes :-( This means also, that defining READ_OVERRUNS is
+ * not possible, since that would require to program the DMA for n*512 - 2
+ * bytes.
+ */
+
+static unsigned long atari_dma_xfer_len( unsigned long wanted_len )
+
+{
+ unsigned long possible_len;
+
+ if (IS_A_TT())
+ /* TT SCSI DMA can transfer arbitrary #bytes */
+ return( wanted_len );
+
+ /* ST DMA chip is stupid -- only multiples of 512 bytes! (and max.
+ * 255*512 bytes, but this should be enough)
+ */
+ possible_len =wanted_len & ~0x1ff;
+ if (possible_len > 255*512)
+ possible_len = 255*512;
+
+#if (NDEBUG & NDEBUG_DMA)
+ if (possible_len != wanted_len)
+ printk( "Sorry, must cut DMA transfer size to %ld bytes instead of %ld\n",
+ possible_len, wanted_len );
+#endif
+
+ return( possible_len );
+}
+
+
+#endif /* REAL_DMA || REAL_DMA_POLL || PSEUDO_DMA */
+
+
+/* NCR5380 register access functions
+ *
+ * There are seperate functions for TT and Falcon, because the access
+ * methods are quite different. The calling macros NCR5380_read and
+ * NCR5380_write call these functions via function pointers.
+ */
+
+static unsigned char atari_scsi_tt_reg_read( unsigned char reg )
+
+{
+ return( tt_scsi_regp[reg * 2] );
+}
+
+static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value )
+
+{
+ tt_scsi_regp[reg * 2] = value;
+}
+
+static unsigned char atari_scsi_falcon_reg_read( unsigned char reg )
+
+{
+ dma_wd.dma_mode_status= (u_short)(0x88 + reg);
+ return( (u_char)dma_wd.fdc_acces_seccount );
+}
+
+static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value )
+
+{
+ dma_wd.dma_mode_status = (u_short)(0x88 + reg);
+ dma_wd.fdc_acces_seccount = (u_short)value;
+}
+
+
+#include "atari_NCR5380.c"
+
+#endif /* CONFIG_ATARI_*_SCSI */
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/scsi/scsi.c linux-0.9pl4/drivers/scsi/scsi.c
--- linux-0.9pl3/drivers/scsi/scsi.c Sun Aug 14 10:30:49 1994
+++ linux-0.9pl4/drivers/scsi/scsi.c Mon Nov 7 22:30:18 1994
@@ -26,7 +26,7 @@
#include "constants.h"
/*
-static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.c,v 1.5 1993/09/24 12:45:18 drew Exp drew $";
+static const char RCSid[] = "$Header: /var/src/linux-0.9pl4/drivers/scsi/RCS/scsi.c,v 1.1 1994/11/08 03:29:28 hamish Exp hamish $";
*/
/* Command groups 3 and 4 are reserved and should never be used. */
@@ -603,13 +603,13 @@
SCpnt->request.nr_sectors -= req->nr_sectors;
req->current_nr_sectors = bh->b_size >> 9;
req->buffer = bh->b_data;
- SCpnt->request.waiting = NULL; /* Wait until whole thing done */
+ SCpnt->request.sem = NULL; /* Wait until whole thing done */
} else
req->dev = -1;
} else {
SCpnt->request.dev = 0xffff; /* Busy, but no request */
- SCpnt->request.waiting = NULL; /* And no one is waiting for the device either */
+ SCpnt->request.sem = NULL; /* And no one is waiting for the device either */
};
SCpnt->use_sg = 0; /* Reset the scatter-gather flag */
@@ -701,7 +701,7 @@
SCpnt->request.nr_sectors -= req->nr_sectors;
req->current_nr_sectors = bh->b_size >> 9;
req->buffer = bh->b_data;
- SCpnt->request.waiting = NULL; /* Wait until whole thing done */
+ SCpnt->request.sem = NULL; /* Wait until whole thing done */
}
else
{
@@ -710,7 +710,7 @@
};
} else {
SCpnt->request.dev = 0xffff; /* Busy */
- SCpnt->request.waiting = NULL; /* And no one is waiting for this to complete */
+ SCpnt->request.sem = NULL; /* And no one is waiting for this to complete */
};
restore_flags (flags);
break;
@@ -1501,7 +1501,10 @@
if(SCset){
oldto = SCset->timeout - used;
+ if(timeout)
SCset->timeout = timeout + used;
+ else
+ SCset->timeout = 0;
};
least = 0xffffffff;
@@ -1667,6 +1670,7 @@
SCpnt->host = scsi_devices[i].host;
SCpnt->target = scsi_devices[i].id;
SCpnt->lun = scsi_devices[i].lun;
+ SCpnt->timeout = 0;
SCpnt->index = i;
SCpnt->request.dev = -1; /* Mark not busy */
SCpnt->use_sg = 0;
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/scsi/scsi.h linux-0.9pl4/drivers/scsi/scsi.h
--- linux-0.9pl3/drivers/scsi/scsi.h Sun Aug 14 10:30:46 1994
+++ linux-0.9pl4/drivers/scsi/scsi.h Sat Nov 5 11:41:45 1994
@@ -452,7 +452,6 @@
{
struct request * req;
struct buffer_head * bh;
- struct task_struct * p;
req = &SCpnt->request;
req->errors = 0;
@@ -484,11 +483,8 @@
return;
};
DEVICE_OFF(req->dev);
- if ((p = req->waiting) != NULL) {
- req->waiting = NULL;
- p->state = TASK_RUNNING;
- if (p->counter > current->counter)
- need_resched = 1;
+ if (req->sem != NULL) {
+ up(req->sem);
}
req->dev = -1;
wake_up(&scsi_devices[SCpnt->index].device_wait);
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/scsi/scsi_ioctl.c linux-0.9pl4/drivers/scsi/scsi_ioctl.c
--- linux-0.9pl3/drivers/scsi/scsi_ioctl.c Sun Aug 14 10:30:49 1994
+++ linux-0.9pl4/drivers/scsi/scsi_ioctl.c Sat Nov 5 11:50:28 1994
@@ -72,16 +72,12 @@
static void scsi_ioctl_done (Scsi_Cmnd * SCpnt)
{
struct request * req;
- struct task_struct * p;
req = &SCpnt->request;
req->dev = 0xfffe; /* Busy, but indicate request done */
- if ((p = req->waiting) != NULL) {
- req->waiting = NULL;
- p->state = TASK_RUNNING;
- if (p->counter > current->counter)
- need_resched = 1;
+ if (req->sem != NULL) {
+ up(req->sem);
}
}
@@ -96,8 +92,10 @@
MAX_RETRIES);
if (SCpnt->request.dev != 0xfffe){
- SCpnt->request.waiting = current;
- current->state = TASK_UNINTERRUPTIBLE;
+ struct semaphore sem = MUTEX_LOCKED;
+ SCpnt->request.sem = &sem;
+ down(&sem);
+ /* Hmm.. Have to ask about this one */
while (SCpnt->request.dev != 0xfffe) schedule();
};
@@ -146,7 +144,7 @@
Scsi_Cmnd * SCpnt;
unsigned char opcode;
int inlen, outlen, cmdlen;
- int needed;
+ int needed, buf_needed;
int result;
if (!buffer)
@@ -158,11 +156,11 @@
cmd_in = (char *) ( ((int *)buffer) + 2);
opcode = get_fs_byte(cmd_in);
- needed = (inlen > outlen ? inlen : outlen);
- if(needed){
- needed = (needed + 511) & ~511;
- if (needed > MAX_BUF) needed = MAX_BUF;
- buf = (char *) scsi_malloc(needed);
+ needed = buf_needed = (inlen > outlen ? inlen : outlen);
+ if(buf_needed){
+ buf_needed = (buf_needed + 511) & ~511;
+ if (buf_needed > MAX_BUF) buf_needed = MAX_BUF;
+ buf = (char *) scsi_malloc(buf_needed);
if (!buf) return -ENOMEM;
} else
buf = NULL;
@@ -180,8 +178,10 @@
MAX_RETRIES);
if (SCpnt->request.dev != 0xfffe){
- SCpnt->request.waiting = current;
- current->state = TASK_UNINTERRUPTIBLE;
+ struct semaphore sem = MUTEX_LOCKED;
+ SCpnt->request.sem = &sem;
+ down(&sem);
+ /* Hmm.. Have to ask about this one */
while (SCpnt->request.dev != 0xfffe) schedule();
};
@@ -201,7 +201,7 @@
};
result = SCpnt->result;
SCpnt->request.dev = -1; /* Mark as not busy */
- if (buf) scsi_free(buf, needed);
+ if (buf) scsi_free(buf, buf_needed);
wake_up(&scsi_devices[SCpnt->index].device_wait);
return result;
#else
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/scsi/sd.c linux-0.9pl4/drivers/scsi/sd.c
--- linux-0.9pl3/drivers/scsi/sd.c Sun Aug 14 10:30:50 1994
+++ linux-0.9pl4/drivers/scsi/sd.c Sat Nov 5 11:41:47 1994
@@ -652,16 +652,12 @@
static void sd_init_done (Scsi_Cmnd * SCpnt)
{
struct request * req;
- struct task_struct * p;
req = &SCpnt->request;
req->dev = 0xfffe; /* Busy, but indicate request done */
- if ((p = req->waiting) != NULL) {
- req->waiting = NULL;
- p->state = TASK_RUNNING;
- if (p->counter > current->counter)
- need_resched = 1;
+ if (req->sem != NULL) {
+ up(req->sem);
}
}
@@ -766,8 +762,10 @@
while(SCpnt->request.dev != 0xfffe);
else
if (SCpnt->request.dev != 0xfffe){
- SCpnt->request.waiting = current;
- current->state = TASK_UNINTERRUPTIBLE;
+ struct semaphore sem = MUTEX_LOCKED;
+ SCpnt->request.sem = &sem;
+ down(&sem);
+ /* Hmm.. Have to ask about this one.. */
while (SCpnt->request.dev != 0xfffe) schedule();
};
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/scsi/sr.c linux-0.9pl4/drivers/scsi/sr.c
--- linux-0.9pl3/drivers/scsi/sr.c Sun Aug 14 10:30:50 1994
+++ linux-0.9pl4/drivers/scsi/sr.c Sat Nov 5 11:41:46 1994
@@ -634,16 +634,12 @@
static void sr_init_done (Scsi_Cmnd * SCpnt)
{
struct request * req;
- struct task_struct * p;
req = &SCpnt->request;
req->dev = 0xfffe; /* Busy, but indicate request done */
- if ((p = req->waiting) != NULL) {
- req->waiting = NULL;
- p->state = TASK_RUNNING;
- if (p->counter > current->counter)
- need_resched = 1;
+ if (req->sem != NULL) {
+ up(req->sem);
}
}
@@ -673,8 +669,10 @@
while(SCpnt->request.dev != 0xfffe);
else
if (SCpnt->request.dev != 0xfffe){
- SCpnt->request.waiting = current;
- current->state = TASK_UNINTERRUPTIBLE;
+ struct semaphore sem = MUTEX_LOCKED;
+ SCpnt->request.sem = &sem;
+ down(&sem);
+ /* Hmm.. Have to ask about this */
while (SCpnt->request.dev != 0xfffe) schedule();
};
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/drivers/scsi/sr_ioctl.c linux-0.9pl4/drivers/scsi/sr_ioctl.c
--- linux-0.9pl3/drivers/scsi/sr_ioctl.c Sun Aug 14 10:30:49 1994
+++ linux-0.9pl4/drivers/scsi/sr_ioctl.c Sat Nov 5 11:41:48 1994
@@ -21,16 +21,12 @@
static void sr_ioctl_done(Scsi_Cmnd * SCpnt)
{
struct request * req;
- struct task_struct * p;
req = &SCpnt->request;
req->dev = 0xfffe; /* Busy, but indicate request done */
- if ((p = req->waiting) != NULL) {
- req->waiting = NULL;
- p->state = TASK_RUNNING;
- if (p->counter > current->counter)
- need_resched = 1;
+ if (req->sem != NULL) {
+ up(req->sem);
}
}
@@ -50,8 +46,10 @@
if (SCpnt->request.dev != 0xfffe){
- SCpnt->request.waiting = current;
- current->state = TASK_UNINTERRUPTIBLE;
+ struct semaphore sem = MUTEX_LOCKED;
+ SCpnt->request.sem = &sem;
+ down(&sem);
+ /* Hmm.. Have to ask about this */
while (SCpnt->request.dev != 0xfffe) schedule();
};
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/fs/buffer.c linux-0.9pl4/fs/buffer.c
--- linux-0.9pl3/fs/buffer.c Sun Aug 14 10:29:52 1994
+++ linux-0.9pl4/fs/buffer.c Mon Nov 7 22:31:29 1994
@@ -48,6 +48,10 @@
#ifdef CONFIG_MCD
extern int check_mcd_media_change(int, int);
#endif
+#ifdef CONFIG_ATARI_ACSI
+extern int check_acsi_media_change(int, int);
+extern int revalidate_acsidisk(int, int);
+#endif
static int grow_buffers(int pri, int size);
@@ -257,6 +261,12 @@
break;
#endif
+#if defined(CONFIG_ATARI_ACSI)
+ case ACSI_MAJOR:
+ i = check_acsi_media_change(dev, 0);
+ break;
+#endif
+
default:
return;
};
@@ -276,6 +286,11 @@
all of the partitions that lie on the disk. */
if (MAJOR(dev) == SCSI_DISK_MAJOR)
revalidate_scsidisk(dev, 0);
+#endif
+#if defined(CONFIG_ATARI_ACSI)
+/* The same is true for ACSI removable harddisks... */
+ if (MAJOR(dev) == ACSI_MAJOR)
+ revalidate_acsidisk(dev, 0);
#endif
}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/fs/minix/symlink.c linux-0.9pl4/fs/minix/symlink.c
--- linux-0.9pl3/fs/minix/symlink.c Tue Sep 27 22:22:40 1994
+++ linux-0.9pl4/fs/minix/symlink.c Mon Oct 10 16:47:50 1994
@@ -101,7 +101,6 @@
i++;
put_fs_byte(c,buffer++);
}
- put_fs_byte(0,buffer++); /* mark EOS */
brelse(bh);
return i;
}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/fs/nfs/Makefile linux-0.9pl4/fs/nfs/Makefile
--- linux-0.9pl3/fs/nfs/Makefile Wed Dec 31 19:00:00 1969
+++ linux-0.9pl4/fs/nfs/Makefile Mon Oct 10 16:48:25 1994
@@ -0,0 +1,27 @@
+#
+# Makefile for the linux nfs-filesystem routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+include ../../.config
+include ../../MakeVars
+
+OBJS= proc.o sock.o inode.o file.o dir.o \
+ symlink.o mmap.o
+
+nfs.o: $(OBJS)
+ $(LD) -r -o nfs.o $(OBJS)
+
+dep:
+ $(CPP) -M *.c > .depend
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/fs/nfs/dir.c linux-0.9pl4/fs/nfs/dir.c
--- linux-0.9pl3/fs/nfs/dir.c Wed Dec 31 19:00:00 1969
+++ linux-0.9pl4/fs/nfs/dir.c Wed Dec 1 07:44:15 1993
@@ -0,0 +1,606 @@
+/*
+ * linux/fs/nfs/dir.c
+ *
+ * Copyright (C) 1992 Rick Sladkey
+ *
+ * nfs directory handling functions
+ */
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/stat.h>
+#include <linux/nfs_fs.h>
+#include <linux/fcntl.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+
+#include <asm/segment.h> /* for fs functions */
+
+static int nfs_dir_read(struct inode *, struct file *filp, char *buf,
+ int count);
+static int nfs_readdir(struct inode *, struct file *, struct dirent *, int);
+static int nfs_lookup(struct inode *dir, const char *name, int len,
+ struct inode **result);
+static int nfs_create(struct inode *dir, const char *name, int len, int mode,
+ struct inode **result);
+static int nfs_mkdir(struct inode *dir, const char *name, int len, int mode);
+static int nfs_rmdir(struct inode *dir, const char *name, int len);
+static int nfs_unlink(struct inode *dir, const char *name, int len);
+static int nfs_symlink(struct inode *inode, const char *name, int len,
+ const char *symname);
+static int nfs_link(struct inode *oldinode, struct inode *dir,
+ const char *name, int len);
+static int nfs_mknod(struct inode *dir, const char *name, int len, int mode,
+ int rdev);
+static int nfs_rename(struct inode *old_dir, const char *old_name,
+ int old_len, struct inode *new_dir, const char *new_name,
+ int new_len);
+
+static struct file_operations nfs_dir_operations = {
+ NULL, /* lseek - default */
+ nfs_dir_read, /* read - bad */
+ NULL, /* write - bad */
+ nfs_readdir, /* readdir */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ NULL, /* no special release code */
+ NULL /* fsync */
+};
+
+struct inode_operations nfs_dir_inode_operations = {
+ &nfs_dir_operations, /* default directory file-ops */
+ nfs_create, /* create */
+ nfs_lookup, /* lookup */
+ nfs_link, /* link */
+ nfs_unlink, /* unlink */
+ nfs_symlink, /* symlink */
+ nfs_mkdir, /* mkdir */
+ nfs_rmdir, /* rmdir */
+ nfs_mknod, /* mknod */
+ nfs_rename, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+static int nfs_dir_read(struct inode *inode, struct file *filp, char *buf,
+ int count)
+{
+ return -EISDIR;
+}
+
+/*
+ * We need to do caching of directory entries to prevent an
+ * incredible amount of RPC traffic. Only the most recent open
+ * directory is cached. This seems sufficient for most purposes.
+ * Technically, we ought to flush the cache on close but this is
+ * not a problem in practice.
+ */
+
+static int nfs_readdir(struct inode *inode, struct file *filp,
+ struct dirent *dirent, int count)
+{
+ static int c_dev = 0;
+ static int c_ino;
+ static int c_size;
+ static struct nfs_entry *c_entry = NULL;
+
+ int result;
+ int i;
+ struct nfs_entry *entry;
+
+ if (!inode || !S_ISDIR(inode->i_mode)) {
+ printk("nfs_readdir: inode is NULL or not a directory\n");
+ return -EBADF;
+ }
+
+ /* initialize cache memory if it hasn't been used before */
+
+ if (c_entry == NULL) {
+ i = sizeof (struct nfs_entry)*NFS_READDIR_CACHE_SIZE;
+ c_entry = (struct nfs_entry *) kmalloc(i, GFP_KERNEL);
+ for (i = 0; i < NFS_READDIR_CACHE_SIZE; i++) {
+ c_entry[i].name = (char *) kmalloc(NFS_MAXNAMLEN + 1,
+ GFP_KERNEL);
+ }
+ }
+ entry = NULL;
+
+ /* try to find it in the cache */
+
+ if (inode->i_dev == c_dev && inode->i_ino == c_ino) {
+ for (i = 0; i < c_size; i++) {
+ if (filp->f_pos == c_entry[i].cookie) {
+ if (i == c_size - 1) {
+ if (c_entry[i].eof)
+ return 0;
+ }
+ else
+ entry = c_entry + i + 1;
+ break;
+ }
+ }
+ }
+
+ /* if we didn't find it in the cache, revert to an nfs call */
+
+ if (!entry) {
+ result = nfs_proc_readdir(NFS_SERVER(inode), NFS_FH(inode),
+ filp->f_pos, NFS_READDIR_CACHE_SIZE, c_entry);
+ if (result < 0) {
+ c_dev = 0;
+ return result;
+ }
+ if (result > 0) {
+ c_dev = inode->i_dev;
+ c_ino = inode->i_ino;
+ c_size = result;
+ entry = c_entry + 0;
+ }
+ }
+
+ /* if we found it in the cache or from an nfs call, return results */
+
+ if (entry) {
+ i = strlen(entry->name);
+ memcpy_tofs(dirent->d_name, entry->name, i + 1);
+ put_fs_long(entry->fileid, &dirent->d_ino);
+ put_fs_word(i, &dirent->d_reclen);
+ filp->f_pos = entry->cookie;
+ return i;
+ }
+ return 0;
+}
+
+/*
+ * Lookup caching is a big win for performance but this is just
+ * a trial to see how well it works on a small scale.
+ * For example, bash does a lookup on ".." 13 times for each path
+ * element when running pwd. Yes, hard to believe but true.
+ * Try pwd in a filesystem mounted with noac.
+ *
+ * It trades a little cpu time and memory for a lot of network bandwidth.
+ * Since the cache is not hashed yet, it is a good idea not to make it too
+ * large because every lookup looks through the entire cache even
+ * though most of them will fail.
+ */
+
+static struct nfs_lookup_cache_entry {
+ int dev;
+ int inode;
+ char filename[NFS_MAXNAMLEN + 1];
+ struct nfs_fh fhandle;
+ struct nfs_fattr fattr;
+ int expiration_date;
+} nfs_lookup_cache[NFS_LOOKUP_CACHE_SIZE];
+
+static struct nfs_lookup_cache_entry *nfs_lookup_cache_index(struct inode *dir,
+ const char *filename)
+{
+ struct nfs_lookup_cache_entry *entry;
+ int i;
+
+ for (i = 0; i < NFS_LOOKUP_CACHE_SIZE; i++) {
+ entry = nfs_lookup_cache + i;
+ if (entry->dev == dir->i_dev && entry->inode == dir->i_ino
+ && !strncmp(filename, entry->filename, NFS_MAXNAMLEN))
+ return entry;
+ }
+ return NULL;
+}
+
+static int nfs_lookup_cache_lookup(struct inode *dir, const char *filename,
+ struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
+{
+ static int nfs_lookup_cache_in_use = 0;
+
+ struct nfs_lookup_cache_entry *entry;
+
+ if (!nfs_lookup_cache_in_use) {
+ memset(nfs_lookup_cache, 0, sizeof(nfs_lookup_cache));
+ nfs_lookup_cache_in_use = 1;
+ }
+ if ((entry = nfs_lookup_cache_index(dir, filename))) {
+ if (jiffies > entry->expiration_date) {
+ entry->dev = 0;
+ return 0;
+ }
+ *fhandle = entry->fhandle;
+ *fattr = entry->fattr;
+ return 1;
+ }
+ return 0;
+}
+
+static void nfs_lookup_cache_add(struct inode *dir, const char *filename,
+ struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
+{
+ static int nfs_lookup_cache_pos = 0;
+ struct nfs_lookup_cache_entry *entry;
+
+ /* compensate for bug in SGI NFS server */
+ if (fattr->size == -1 || fattr->uid == -1 || fattr->gid == -1
+ || fattr->atime.seconds == -1 || fattr->mtime.seconds == -1)
+ return;
+ if (!(entry = nfs_lookup_cache_index(dir, filename))) {
+ entry = nfs_lookup_cache + nfs_lookup_cache_pos++;
+ if (nfs_lookup_cache_pos == NFS_LOOKUP_CACHE_SIZE)
+ nfs_lookup_cache_pos = 0;
+ }
+ entry->dev = dir->i_dev;
+ entry->inode = dir->i_ino;
+ strcpy(entry->filename, filename);
+ entry->fhandle = *fhandle;
+ entry->fattr = *fattr;
+ entry->expiration_date = jiffies + (S_ISDIR(fattr->mode)
+ ? NFS_SERVER(dir)->acdirmax : NFS_SERVER(dir)->acregmax);
+}
+
+static void nfs_lookup_cache_remove(struct inode *dir, struct inode *inode,
+ const char *filename)
+{
+ struct nfs_lookup_cache_entry *entry;
+ int dev;
+ int fileid;
+ int i;
+
+ if (inode) {
+ dev = inode->i_dev;
+ fileid = inode->i_ino;
+ }
+ else if ((entry = nfs_lookup_cache_index(dir, filename))) {
+ dev = entry->dev;
+ fileid = entry->fattr.fileid;
+ }
+ else
+ return;
+ for (i = 0; i < NFS_LOOKUP_CACHE_SIZE; i++) {
+ entry = nfs_lookup_cache + i;
+ if (entry->dev == dev && entry->fattr.fileid == fileid)
+ entry->dev = 0;
+ }
+}
+
+static void nfs_lookup_cache_refresh(struct inode *file,
+ struct nfs_fattr *fattr)
+{
+ struct nfs_lookup_cache_entry *entry;
+ int dev = file->i_dev;
+ int fileid = file->i_ino;
+ int i;
+
+ for (i = 0; i < NFS_LOOKUP_CACHE_SIZE; i++) {
+ entry = nfs_lookup_cache + i;
+ if (entry->dev == dev && entry->fattr.fileid == fileid)
+ entry->fattr = *fattr;
+ }
+}
+
+static int nfs_lookup(struct inode *dir, const char *__name, int len,
+ struct inode **result)
+{
+ struct nfs_fh fhandle;
+ struct nfs_fattr fattr;
+ char name[len > NFS_MAXNAMLEN? 1 : len+1];
+ int error;
+
+ *result = NULL;
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk("nfs_lookup: inode is NULL or not a directory\n");
+ iput(dir);
+ return -ENOENT;
+ }
+ if (len > NFS_MAXNAMLEN) {
+ iput(dir);
+ return -ENAMETOOLONG;
+ }
+ memcpy(name,__name,len);
+ name[len] = '\0';
+ if (len == 1 && name[0] == '.') { /* cheat for "." */
+ *result = dir;
+ return 0;
+ }
+ if ((NFS_SERVER(dir)->flags & NFS_MOUNT_NOAC)
+ || !nfs_lookup_cache_lookup(dir, name, &fhandle, &fattr)) {
+ if ((error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir),
+ name, &fhandle, &fattr))) {
+ iput(dir);
+ return error;
+ }
+ nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
+ }
+ if (!(*result = nfs_fhget(dir->i_sb, &fhandle, &fattr))) {
+ iput(dir);
+ return -EACCES;
+ }
+ iput(dir);
+ return 0;
+}
+
+static int nfs_create(struct inode *dir, const char *name, int len, int mode,
+ struct inode **result)
+{
+ struct nfs_sattr sattr;
+ struct nfs_fattr fattr;
+ struct nfs_fh fhandle;
+ int error;
+
+ *result = NULL;
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk("nfs_create: inode is NULL or not a directory\n");
+ iput(dir);
+ return -ENOENT;
+ }
+ if (len > NFS_MAXNAMLEN) {
+ iput(dir);
+ return -ENAMETOOLONG;
+ }
+ sattr.mode = mode;
+ sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
+ sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+ if ((error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
+ name, &sattr, &fhandle, &fattr))) {
+ iput(dir);
+ return error;
+ }
+ if (!(*result = nfs_fhget(dir->i_sb, &fhandle, &fattr))) {
+ iput(dir);
+ return -EACCES;
+ }
+ nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
+ iput(dir);
+ return 0;
+}
+
+static int nfs_mknod(struct inode *dir, const char *name, int len,
+ int mode, int rdev)
+{
+ struct nfs_sattr sattr;
+ struct nfs_fattr fattr;
+ struct nfs_fh fhandle;
+ int error;
+
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk("nfs_mknod: inode is NULL or not a directory\n");
+ iput(dir);
+ return -ENOENT;
+ }
+ if (len > NFS_MAXNAMLEN) {
+ iput(dir);
+ return -ENAMETOOLONG;
+ }
+ sattr.mode = mode;
+ sattr.uid = sattr.gid = (unsigned) -1;
+ if (S_ISCHR(mode) || S_ISBLK(mode))
+ sattr.size = rdev; /* get out your barf bag */
+ else
+ sattr.size = (unsigned) -1;
+ sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+ error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir),
+ name, &sattr, &fhandle, &fattr);
+ if (!error)
+ nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
+ iput(dir);
+ return error;
+}
+
+static int nfs_mkdir(struct inode *dir, const char *name, int len, int mode)
+{
+ struct nfs_sattr sattr;
+ struct nfs_fattr fattr;
+ struct nfs_fh fhandle;
+ int error;
+
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk("nfs_mkdir: inode is NULL or not a directory\n");
+ iput(dir);
+ return -ENOENT;
+ }
+ if (len > NFS_MAXNAMLEN) {
+ iput(dir);
+ return -ENAMETOOLONG;
+ }
+ sattr.mode = mode;
+ sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
+ sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+ error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir),
+ name, &sattr, &fhandle, &fattr);
+ if (!error)
+ nfs_lookup_cache_add(dir, name, &fhandle, &fattr);
+ iput(dir);
+ return error;
+}
+
+static int nfs_rmdir(struct inode *dir, const char *name, int len)
+{
+ int error;
+
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk("nfs_rmdir: inode is NULL or not a directory\n");
+ iput(dir);
+ return -ENOENT;
+ }
+ if (len > NFS_MAXNAMLEN) {
+ iput(dir);
+ return -ENAMETOOLONG;
+ }
+ error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), name);
+ if (!error)
+ nfs_lookup_cache_remove(dir, NULL, name);
+ iput(dir);
+ return error;
+}
+
+static int nfs_unlink(struct inode *dir, const char *name, int len)
+{
+ int error;
+
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk("nfs_unlink: inode is NULL or not a directory\n");
+ iput(dir);
+ return -ENOENT;
+ }
+ if (len > NFS_MAXNAMLEN) {
+ iput(dir);
+ return -ENAMETOOLONG;
+ }
+ error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), name);
+ if (!error)
+ nfs_lookup_cache_remove(dir, NULL, name);
+ iput(dir);
+ return error;
+}
+
+static int nfs_symlink(struct inode *dir, const char *name, int len,
+ const char *symname)
+{
+ struct nfs_sattr sattr;
+ int error;
+
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk("nfs_symlink: inode is NULL or not a directory\n");
+ iput(dir);
+ return -ENOENT;
+ }
+ if (len > NFS_MAXNAMLEN) {
+ iput(dir);
+ return -ENAMETOOLONG;
+ }
+ if (strlen(symname) > NFS_MAXPATHLEN) {
+ iput(dir);
+ return -ENAMETOOLONG;
+ }
+ sattr.mode = S_IFLNK | S_IRWXUGO; /* SunOS 4.1.2 crashes without this! */
+ sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
+ sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+ error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dir),
+ name, symname, &sattr);
+ iput(dir);
+ return error;
+}
+
+static int nfs_link(struct inode *oldinode, struct inode *dir,
+ const char *name, int len)
+{
+ int error;
+
+ if (!oldinode) {
+ printk("nfs_link: old inode is NULL\n");
+ iput(oldinode);
+ iput(dir);
+ return -ENOENT;
+ }
+ if (!dir || !S_ISDIR(dir->i_mode)) {
+ printk("nfs_link: dir is NULL or not a directory\n");
+ iput(oldinode);
+ iput(dir);
+ return -ENOENT;
+ }
+ if (len > NFS_MAXNAMLEN) {
+ iput(oldinode);
+ iput(dir);
+ return -ENAMETOOLONG;
+ }
+ error = nfs_proc_link(NFS_SERVER(oldinode), NFS_FH(oldinode),
+ NFS_FH(dir), name);
+ if (!error)
+ nfs_lookup_cache_remove(dir, oldinode, NULL);
+ iput(oldinode);
+ iput(dir);
+ return error;
+}
+
+static int nfs_rename(struct inode *old_dir, const char *old_name, int old_len,
+ struct inode *new_dir, const char *new_name, int new_len)
+{
+ int error;
+
+ if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
+ printk("nfs_rename: old inode is NULL or not a directory\n");
+ iput(old_dir);
+ iput(new_dir);
+ return -ENOENT;
+ }
+ if (!new_dir || !S_ISDIR(new_dir->i_mode)) {
+ printk("nfs_rename: new inode is NULL or not a directory\n");
+ iput(old_dir);
+ iput(new_dir);
+ return -ENOENT;
+ }
+ if (old_len > NFS_MAXNAMLEN || new_len > NFS_MAXNAMLEN) {
+ iput(old_dir);
+ iput(new_dir);
+ return -ENAMETOOLONG;
+ }
+ error = nfs_proc_rename(NFS_SERVER(old_dir),
+ NFS_FH(old_dir), old_name,
+ NFS_FH(new_dir), new_name);
+ if (!error) {
+ nfs_lookup_cache_remove(old_dir, NULL, old_name);
+ nfs_lookup_cache_remove(new_dir, NULL, new_name);
+ }
+ iput(old_dir);
+ iput(new_dir);
+ return error;
+}
+
+/*
+ * Many nfs protocol calls return the new file attributes after
+ * an operation. Here we update the inode to reflect the state
+ * of the server's inode.
+ */
+
+void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
+{
+ int was_empty;
+
+ if (!inode || !fattr) {
+ printk("nfs_refresh_inode: inode or fattr is NULL\n");
+ return;
+ }
+ if (inode->i_ino != fattr->fileid) {
+ printk("nfs_refresh_inode: inode number mismatch\n");
+ return;
+ }
+ was_empty = inode->i_mode == 0;
+ inode->i_mode = fattr->mode;
+ inode->i_nlink = fattr->nlink;
+ inode->i_uid = fattr->uid;
+ inode->i_gid = fattr->gid;
+ inode->i_size = fattr->size;
+ inode->i_blksize = fattr->blocksize;
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ inode->i_rdev = fattr->rdev;
+ else
+ inode->i_rdev = 0;
+ inode->i_blocks = fattr->blocks;
+ inode->i_atime = fattr->atime.seconds;
+ inode->i_mtime = fattr->mtime.seconds;
+ inode->i_ctime = fattr->ctime.seconds;
+ if (was_empty) {
+ if (S_ISREG(inode->i_mode))
+ inode->i_op = &nfs_file_inode_operations;
+ else if (S_ISDIR(inode->i_mode))
+ inode->i_op = &nfs_dir_inode_operations;
+ else if (S_ISLNK(inode->i_mode))
+ inode->i_op = &nfs_symlink_inode_operations;
+ else if (S_ISCHR(inode->i_mode))
+ inode->i_op = &chrdev_inode_operations;
+ else if (S_ISBLK(inode->i_mode))
+ inode->i_op = &blkdev_inode_operations;
+ else if (S_ISFIFO(inode->i_mode))
+ init_fifo(inode);
+ else
+ inode->i_op = NULL;
+ }
+ nfs_lookup_cache_refresh(inode, fattr);
+}
+
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/fs/nfs/file.c linux-0.9pl4/fs/nfs/file.c
--- linux-0.9pl3/fs/nfs/file.c Wed Dec 31 19:00:00 1969
+++ linux-0.9pl4/fs/nfs/file.c Wed Dec 1 07:44:15 1993
@@ -0,0 +1,163 @@
+/*
+ * linux/fs/nfs/file.c
+ *
+ * Copyright (C) 1992 Rick Sladkey
+ *
+ * nfs regular file handling functions
+ */
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/nfs_fs.h>
+#include <linux/malloc.h>
+
+static int nfs_file_read(struct inode *, struct file *, char *, int);
+static int nfs_file_write(struct inode *, struct file *, char *, int);
+static int nfs_fsync(struct inode *, struct file *);
+extern int nfs_mmap(struct inode * inode, struct file * file,
+ unsigned long addr, size_t len, int prot, unsigned long off);
+
+static struct file_operations nfs_file_operations = {
+ NULL, /* lseek - default */
+ nfs_file_read, /* read */
+ nfs_file_write, /* write */
+ NULL, /* readdir - bad */
+ NULL, /* select - default */
+ NULL, /* ioctl - default */
+ nfs_mmap, /* mmap */
+ NULL, /* no special open is needed */
+ NULL, /* release */
+ nfs_fsync, /* fsync */
+};
+
+struct inode_operations nfs_file_inode_operations = {
+ &nfs_file_operations, /* default file operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ NULL /* truncate */
+};
+
+static int nfs_fsync(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int nfs_file_read(struct inode *inode, struct file *file, char *buf,
+ int count)
+{
+ int result;
+ int hunk;
+ int i;
+ int n;
+ struct nfs_fattr fattr;
+ char *data;
+ off_t pos;
+
+ if (!inode) {
+ printk("nfs_file_read: inode = NULL\n");
+ return -EINVAL;
+ }
+ if (!S_ISREG(inode->i_mode)) {
+ printk("nfs_file_read: read from non-file, mode %07o\n",
+ inode->i_mode);
+ return -EINVAL;
+ }
+ pos = file->f_pos;
+ if (file->f_pos + count > inode->i_size)
+ count = inode->i_size - pos;
+ if (count <= 0)
+ return 0;
+ n = NFS_SERVER(inode)->rsize;
+ data = (char *) kmalloc(n, GFP_KERNEL);
+ for (i = 0; i < count; i += n) {
+ hunk = count - i;
+ if (hunk > n)
+ hunk = n;
+ result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode),
+ pos, hunk, data, &fattr);
+ if (result < 0) {
+ kfree_s(data, n);
+ return result;
+ }
+ memcpy_tofs(buf, data, result);
+ pos += result;
+ buf += result;
+ if (result < n) {
+ i += result;
+ break;
+ }
+ }
+ file->f_pos = pos;
+ kfree_s(data, n);
+ nfs_refresh_inode(inode, &fattr);
+ return i;
+}
+
+static int nfs_file_write(struct inode *inode, struct file *file, char *buf,
+ int count)
+{
+ int result;
+ int hunk;
+ int i;
+ int n;
+ struct nfs_fattr fattr;
+ char *data;
+ int pos;
+
+ if (!inode) {
+ printk("nfs_file_write: inode = NULL\n");
+ return -EINVAL;
+ }
+ if (!S_ISREG(inode->i_mode)) {
+ printk("nfs_file_write: write to non-file, mode %07o\n",
+ inode->i_mode);
+ return -EINVAL;
+ }
+ if (count <= 0)
+ return 0;
+ pos = file->f_pos;
+ if (file->f_flags & O_APPEND)
+ pos = inode->i_size;
+ n = NFS_SERVER(inode)->wsize;
+ data = (char *) kmalloc(n, GFP_KERNEL);
+ for (i = 0; i < count; i += n) {
+ hunk = count - i;
+ if (hunk >= n)
+ hunk = n;
+ memcpy_fromfs(data, buf, hunk);
+ result = nfs_proc_write(NFS_SERVER(inode), NFS_FH(inode),
+ pos, hunk, data, &fattr);
+ if (result < 0) {
+ kfree_s(data, n);
+ return result;
+ }
+ pos += hunk;
+ buf += hunk;
+ if (hunk < n) {
+ i += hunk;
+ break;
+ }
+ }
+ file->f_pos = pos;
+ kfree_s(data, n);
+ nfs_refresh_inode(inode, &fattr);
+ return i;
+}
+
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/fs/nfs/inode.c linux-0.9pl4/fs/nfs/inode.c
--- linux-0.9pl3/fs/nfs/inode.c Wed Dec 31 19:00:00 1969
+++ linux-0.9pl4/fs/nfs/inode.c Wed Dec 1 07:44:15 1993
@@ -0,0 +1,233 @@
+/*
+ * linux/fs/nfs/inode.c
+ *
+ * Copyright (C) 1992 Rick Sladkey
+ *
+ * nfs inode and superblock handling functions
+ */
+
+#include <asm/system.h>
+#include <asm/segment.h>
+
+#include <linux/sched.h>
+#include <linux/nfs_fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/locks.h>
+
+extern int close_fp(struct file *filp, unsigned int fd);
+
+static int nfs_notify_change(int, struct inode *);
+static void nfs_put_inode(struct inode *);
+static void nfs_put_super(struct super_block *);
+static void nfs_statfs(struct super_block *, struct statfs *);
+
+static struct super_operations nfs_sops = {
+ NULL, /* read inode */
+ nfs_notify_change, /* notify change */
+ NULL, /* write inode */
+ nfs_put_inode, /* put inode */
+ nfs_put_super, /* put superblock */
+ NULL, /* write superblock */
+ nfs_statfs, /* stat filesystem */
+ NULL
+};
+
+static void nfs_put_inode(struct inode * inode)
+{
+ clear_inode(inode);
+}
+
+void nfs_put_super(struct super_block *sb)
+{
+ /* No locks should be open on this, so 0 should be safe as a fd. */
+ close_fp(sb->u.nfs_sb.s_server.file, 0);
+ lock_super(sb);
+ sb->s_dev = 0;
+ unlock_super(sb);
+}
+
+/*
+ * The way this works is that the mount process passes a structure
+ * in the data argument which contains an open socket to the NFS
+ * server and the root file handle obtained from the server's mount
+ * daemon. We stash theses away in the private superblock fields.
+ * Later we can add other mount parameters like caching values.
+ */
+
+struct super_block *nfs_read_super(struct super_block *sb, void *raw_data,
+ int silent)
+{
+ struct nfs_mount_data *data = (struct nfs_mount_data *) raw_data;
+ struct nfs_server *server;
+ unsigned int fd;
+ struct file *filp;
+ dev_t dev = sb->s_dev;
+
+ if (!data) {
+ printk("nfs_read_super: missing data argument\n");
+ sb->s_dev = 0;
+ return NULL;
+ }
+ fd = data->fd;
+ if (data->version != NFS_MOUNT_VERSION) {
+ printk("nfs warning: mount version %s than kernel\n",
+ data->version < NFS_MOUNT_VERSION ? "older" : "newer");
+ }
+ if (fd >= NR_OPEN || !(filp = current->filp[fd])) {
+ printk("nfs_read_super: invalid file descriptor\n");
+ sb->s_dev = 0;
+ return NULL;
+ }
+ if (!S_ISSOCK(filp->f_inode->i_mode)) {
+ printk("nfs_read_super: not a socket\n");
+ sb->s_dev = 0;
+ return NULL;
+ }
+ filp->f_count++;
+ lock_super(sb);
+ sb->s_blocksize = 1024; /* XXX */
+ sb->s_blocksize_bits = 10;
+ sb->s_magic = NFS_SUPER_MAGIC;
+ sb->s_dev = dev;
+ sb->s_op = &nfs_sops;
+ server = &sb->u.nfs_sb.s_server;
+ server->file = filp;
+ server->lock = 0;
+ server->wait = NULL;
+ server->flags = data->flags;
+ server->rsize = data->rsize;
+ if (server->rsize <= 0)
+ server->rsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
+ else if (server->rsize >= NFS_MAX_FILE_IO_BUFFER_SIZE)
+ server->rsize = NFS_MAX_FILE_IO_BUFFER_SIZE;
+ server->wsize = data->wsize;
+ if (server->wsize <= 0)
+ server->wsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
+ else if (server->wsize >= NFS_MAX_FILE_IO_BUFFER_SIZE)
+ server->wsize = NFS_MAX_FILE_IO_BUFFER_SIZE;
+ server->timeo = data->timeo*HZ/10;
+ server->retrans = data->retrans;
+ server->acregmin = data->acregmin*HZ;
+ server->acregmax = data->acregmax*HZ;
+ server->acdirmin = data->acdirmin*HZ;
+ server->acdirmax = data->acdirmax*HZ;
+ strcpy(server->hostname, data->hostname);
+ sb->u.nfs_sb.s_root = data->root;
+ unlock_super(sb);
+ if (!(sb->s_mounted = nfs_fhget(sb, &data->root, NULL))) {
+ sb->s_dev = 0;
+ printk("nfs_read_super: get root inode failed\n");
+ return NULL;
+ }
+ return sb;
+}
+
+void nfs_statfs(struct super_block *sb, struct statfs *buf)
+{
+ int error;
+ struct nfs_fsinfo res;
+
+ put_fs_long(NFS_SUPER_MAGIC, &buf->f_type);
+ error = nfs_proc_statfs(&sb->u.nfs_sb.s_server, &sb->u.nfs_sb.s_root,
+ &res);
+ if (error) {
+ printk("nfs_statfs: statfs error = %d\n", -error);
+ res.bsize = res.blocks = res.bfree = res.bavail = 0;
+ }
+ put_fs_long(res.bsize, &buf->f_bsize);
+ put_fs_long(res.blocks, &buf->f_blocks);
+ put_fs_long(res.bfree, &buf->f_bfree);
+ put_fs_long(res.bavail, &buf->f_bavail);
+ put_fs_long(0, &buf->f_files);
+ put_fs_long(0, &buf->f_ffree);
+ /* We should really try to interrogate the remote server to find
+ it's maximum name length here */
+ put_fs_long(NAME_MAX, &buf->f_namelen);
+}
+
+/*
+ * This is our own version of iget that looks up inodes by file handle
+ * instead of inode number. We use this technique instead of using
+ * the vfs read_inode function because there is no way to pass the
+ * file handle or current attributes into the read_inode function.
+ * We just have to be careful not to subvert iget's special handling
+ * of mount points.
+ */
+
+struct inode *nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
+{
+ struct nfs_fattr newfattr;
+ int error;
+ struct inode *inode;
+
+ if (!sb) {
+ printk("nfs_fhget: super block is NULL\n");
+ return NULL;
+ }
+ if (!fattr) {
+ error = nfs_proc_getattr(&sb->u.nfs_sb.s_server, fhandle,
+ &newfattr);
+ if (error) {
+ printk("nfs_fhget: getattr error = %d\n", -error);
+ return NULL;
+ }
+ fattr = &newfattr;
+ }
+ if (!(inode = iget(sb, fattr->fileid))) {
+ printk("nfs_fhget: iget failed\n");
+ return NULL;
+ }
+ if (inode->i_dev == sb->s_dev) {
+ if (inode->i_ino != fattr->fileid) {
+ printk("nfs_fhget: unexpected inode from iget\n");
+ return inode;
+ }
+ *NFS_FH(inode) = *fhandle;
+ nfs_refresh_inode(inode, fattr);
+ }
+ return inode;
+}
+
+int nfs_notify_change(int flags, struct inode *inode)
+{
+ struct nfs_sattr sattr;
+ struct nfs_fattr fattr;
+ int error;
+
+ if (flags & NOTIFY_MODE)
+ sattr.mode = inode->i_mode;
+ else
+ sattr.mode = (unsigned) -1;
+ if (flags & NOTIFY_UIDGID) {
+ sattr.uid = inode->i_uid;
+ sattr.gid = inode->i_gid;
+ }
+ else
+ sattr.uid = sattr.gid = (unsigned) -1;
+ if (flags & NOTIFY_SIZE)
+ sattr.size = S_ISREG(inode->i_mode) ? inode->i_size : -1;
+ else
+ sattr.size = (unsigned) -1;
+ if (flags & NOTIFY_TIME) {
+ sattr.mtime.seconds = inode->i_mtime;
+ sattr.mtime.useconds = 0;
+ sattr.atime.seconds = inode->i_atime;
+ sattr.atime.useconds = 0;
+ }
+ else {
+ sattr.mtime.seconds = sattr.mtime.useconds = (unsigned) -1;
+ sattr.atime.seconds = sattr.atime.useconds = (unsigned) -1;
+ }
+ error = nfs_proc_setattr(NFS_SERVER(inode), NFS_FH(inode),
+ &sattr, &fattr);
+ if (!error)
+ nfs_refresh_inode(inode, &fattr);
+ inode->i_dirt = 0;
+ return error;
+}
+
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/fs/nfs/mmap.c linux-0.9pl4/fs/nfs/mmap.c
--- linux-0.9pl3/fs/nfs/mmap.c Wed Dec 31 19:00:00 1969
+++ linux-0.9pl4/fs/nfs/mmap.c Mon Oct 10 16:48:26 1994
@@ -0,0 +1,161 @@
+/*
+ * fs/nfs/mmap.c by Jon Tombs 15 Aug 1993
+ *
+ * This code is from
+ * linux/mm/mmap.c which was written by obz, Linus and Eric
+ * and
+ * linux/mm/memory.c by Linus Torvalds and others
+ *
+ * Copyright (C) 1993
+ *
+ */
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/shm.h>
+#include <linux/errno.h>
+#include <linux/mman.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/nfs_fs.h>
+
+#include <asm/segment.h>
+#include <asm/system.h>
+
+extern int share_page(struct vm_area_struct * area, struct task_struct * tsk,
+ struct inode * inode, unsigned long address, unsigned long error_code,
+ unsigned long newpage);
+
+extern unsigned long put_page(struct task_struct * tsk,unsigned long page,
+ unsigned long address,int prot);
+
+static void nfs_file_mmap_nopage(int error_code, struct vm_area_struct * area,
+ unsigned long address);
+
+extern void file_mmap_free(struct vm_area_struct * area);
+extern int file_mmap_share(struct vm_area_struct * from, struct vm_area_struct * to,
+ unsigned long address);
+
+struct vm_operations_struct nfs_file_mmap = {
+ NULL, /* open */
+ file_mmap_free, /* close */
+ nfs_file_mmap_nopage, /* nopage */
+ NULL, /* wppage */
+ file_mmap_share, /* share */
+ NULL, /* unmap */
+};
+
+
+/* This is used for a general mmap of a nfs file */
+int nfs_mmap(struct inode * inode, struct file * file,
+ unsigned long addr, size_t len, int prot, unsigned long off)
+{
+ struct vm_area_struct * mpnt;
+
+ if (prot & PAGE_RW) /* only PAGE_COW or read-only supported now */
+ return -EINVAL;
+ if (off & (inode->i_sb->s_blocksize - 1))
+ return -EINVAL;
+ if (!inode->i_sb || !S_ISREG(inode->i_mode))
+ return -EACCES;
+ if (!IS_RDONLY(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
+
+ mpnt = (struct vm_area_struct * ) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+ if (!mpnt)
+ return -ENOMEM;
+
+ unmap_page_range(addr, len);
+ mpnt->vm_task = current;
+ mpnt->vm_start = addr;
+ mpnt->vm_end = addr + len;
+ mpnt->vm_page_prot = prot;
+ mpnt->vm_share = NULL;
+ mpnt->vm_inode = inode;
+ inode->i_count++;
+ mpnt->vm_offset = off;
+ mpnt->vm_ops = &nfs_file_mmap;
+ insert_vm_struct(current, mpnt);
+ merge_segments(current->mmap, NULL, NULL);
+ return 0;
+}
+
+
+static void nfs_file_mmap_nopage(int error_code, struct vm_area_struct * area,
+ unsigned long address)
+{
+ struct inode * inode = area->vm_inode;
+ unsigned int clear;
+ unsigned long page;
+ unsigned long tmp;
+ int n;
+ int i;
+ int pos;
+ struct nfs_fattr fattr;
+
+ address &= PAGE_MASK;
+ pos = address - area->vm_start + area->vm_offset;
+
+ page = get_free_page(GFP_KERNEL);
+ if (share_page(area, area->vm_task, inode, address, error_code, page)) {
+ ++area->vm_task->min_flt;
+ return;
+ }
+
+ ++area->vm_task->maj_flt;
+ if (!page) {
+ oom(current);
+ put_page(area->vm_task, BAD_PAGE, address, PAGE_PRIVATE);
+ return;
+ }
+
+ clear = 0;
+ if (address + PAGE_SIZE > area->vm_end) {
+ clear = address + PAGE_SIZE - area->vm_end;
+ }
+
+ n = NFS_SERVER(inode)->rsize; /* what we can read in one go */
+
+ for (i = 0; i < (PAGE_SIZE - clear); i += n) {
+ int hunk, result;
+
+ hunk = PAGE_SIZE - i;
+ if (hunk > n)
+ hunk = n;
+ result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode),
+ pos, hunk, (char *) (page + i), &fattr);
+ if (result < 0)
+ break;
+ pos += result;
+ if (result < n) {
+ i += result;
+ break;
+ }
+ }
+
+#ifdef doweneedthishere
+ nfs_refresh_inode(inode, &fattr);
+#endif
+
+#if defined (__i386__)
+ if (!(error_code & PAGE_RW))
+#elif defined (__mc68000__)
+ if (!(error_code & 1)) /* ????? */
+#endif
+ {
+ if (share_page(area, area->vm_task, inode, address, error_code, page))
+ return;
+ }
+
+ tmp = page + PAGE_SIZE;
+ while (clear--) {
+ *(char *)--tmp = 0;
+ }
+ if (put_page(area->vm_task,page,address,area->vm_page_prot))
+ return;
+ free_page(page);
+ oom(current);
+}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/fs/nfs/proc.c linux-0.9pl4/fs/nfs/proc.c
--- linux-0.9pl3/fs/nfs/proc.c Wed Dec 31 19:00:00 1969
+++ linux-0.9pl4/fs/nfs/proc.c Mon Feb 14 05:48:36 1994
@@ -0,0 +1,873 @@
+/*
+ * linux/fs/nfs/proc.c
+ *
+ * Copyright (C) 1992, 1993, 1994 Rick Sladkey
+ *
+ * OS-independent nfs remote procedure call functions
+ */
+
+/*
+ * Defining NFS_PROC_DEBUG causes a lookup of a file named
+ * "xyzzy" to toggle debugging. Just cd to an NFS-mounted
+ * filesystem and type 'ls xyzzy' to turn on debugging.
+ */
+
+#if 0
+#define NFS_PROC_DEBUG
+#endif
+
+#include <linux/config.h>
+#include <linux/param.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/nfs_fs.h>
+#include <linux/utsname.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/in.h>
+
+#ifdef NFS_PROC_DEBUG
+
+static int proc_debug = 0;
+#define PRINTK(format, args...) \
+ do { \
+ if (proc_debug) \
+ printk(format , ## args); \
+ } while (0)
+
+#else /* !NFS_PROC_DEBUG */
+
+#define PRINTK(format, args...) do ; while (0)
+
+#endif /* !NFS_PROC_DEBUG */
+
+static int *nfs_rpc_header(int *p, int procedure, int ruid);
+static int *nfs_rpc_verify(int *p);
+static int nfs_stat_to_errno(int stat);
+
+/*
+ * Our memory allocation and release functions.
+ */
+
+static inline int *nfs_rpc_alloc(void)
+{
+ return (int *) __get_free_page(GFP_KERNEL);
+}
+
+static inline void nfs_rpc_free(int *p)
+{
+ free_page((long) p);
+}
+
+/*
+ * Here are a bunch of xdr encode/decode functions that convert
+ * between machine dependent and xdr data formats.
+ */
+
+static inline int *xdr_encode_fhandle(int *p, struct nfs_fh *fhandle)
+{
+ *((struct nfs_fh *) p) = *fhandle;
+ p += (sizeof (*fhandle) + 3) >> 2;
+ return p;
+}
+
+static inline int *xdr_decode_fhandle(int *p, struct nfs_fh *fhandle)
+{
+ *fhandle = *((struct nfs_fh *) p);
+ p += (sizeof (*fhandle) + 3) >> 2;
+ return p;
+}
+
+static inline int *xdr_encode_string(int *p, const char *string)
+{
+ int len, quadlen;
+
+ len = strlen(string);
+ quadlen = (len + 3) >> 2;
+ *p++ = htonl(len);
+ memcpy((char *) p, string, len);
+ memset(((char *) p) + len, '\0', (quadlen << 2) - len);
+ p += quadlen;
+ return p;
+}
+
+static inline int *xdr_decode_string(int *p, char *string, int maxlen)
+{
+ unsigned int len;
+
+ len = ntohl(*p++);
+ if (len > maxlen)
+ return NULL;
+ memcpy(string, (char *) p, len);
+ string[len] = '\0';
+ p += (len + 3) >> 2;
+ return p;
+}
+
+static inline int *xdr_encode_data(int *p, char *data, int len)
+{
+ int quadlen;
+
+ quadlen = (len + 3) >> 2;
+ *p++ = htonl(len);
+ memcpy((char *) p, data, len);
+ memset(((char *) p) + len, '\0', (quadlen << 2) - len);
+ p += quadlen;
+ return p;
+}
+
+static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen)
+{
+ unsigned int len;
+
+ len = *lenp = ntohl(*p++);
+ if (len > maxlen)
+ return NULL;
+ memcpy(data, (char *) p, len);
+ p += (len + 3) >> 2;
+ return p;
+}
+
+static int *xdr_decode_fattr(int *p, struct nfs_fattr *fattr)
+{
+ fattr->type = (enum nfs_ftype) ntohl(*p++);
+ fattr->mode = ntohl(*p++);
+ fattr->nlink = ntohl(*p++);
+ fattr->uid = ntohl(*p++);
+ fattr->gid = ntohl(*p++);
+ fattr->size = ntohl(*p++);
+ fattr->blocksize = ntohl(*p++);
+ fattr->rdev = ntohl(*p++);
+ fattr->blocks = ntohl(*p++);
+ fattr->fsid = ntohl(*p++);
+ fattr->fileid = ntohl(*p++);
+ fattr->atime.seconds = ntohl(*p++);
+ fattr->atime.useconds = ntohl(*p++);
+ fattr->mtime.seconds = ntohl(*p++);
+ fattr->mtime.useconds = ntohl(*p++);
+ fattr->ctime.seconds = ntohl(*p++);
+ fattr->ctime.useconds = ntohl(*p++);
+ return p;
+}
+
+static int *xdr_encode_sattr(int *p, struct nfs_sattr *sattr)
+{
+ *p++ = htonl(sattr->mode);
+ *p++ = htonl(sattr->uid);
+ *p++ = htonl(sattr->gid);
+ *p++ = htonl(sattr->size);
+ *p++ = htonl(sattr->atime.seconds);
+ *p++ = htonl(sattr->atime.useconds);
+ *p++ = htonl(sattr->mtime.seconds);
+ *p++ = htonl(sattr->mtime.useconds);
+ return p;
+}
+
+static int *xdr_decode_entry(int *p, struct nfs_entry *entry)
+{
+ entry->fileid = ntohl(*p++);
+ if (!(p = xdr_decode_string(p, entry->name, NFS_MAXNAMLEN)))
+ return NULL;
+ entry->cookie = ntohl(*p++);
+ entry->eof = 0;
+ return p;
+}
+
+static int *xdr_decode_fsinfo(int *p, struct nfs_fsinfo *res)
+{
+ res->tsize = ntohl(*p++);
+ res->bsize = ntohl(*p++);
+ res->blocks = ntohl(*p++);
+ res->bfree = ntohl(*p++);
+ res->bavail = ntohl(*p++);
+ return p;
+}
+
+/*
+ * One function for each procedure in the NFS protocol.
+ */
+
+int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr)
+{
+ int *p, *p0;
+ int status;
+ int ruid = 0;
+
+ PRINTK("NFS call getattr\n");
+ if (!(p0 = nfs_rpc_alloc()))
+ return -EIO;
+retry:
+ p = nfs_rpc_header(p0, NFSPROC_GETATTR, ruid);
+ p = xdr_encode_fhandle(p, fhandle);
+ if ((status = nfs_rpc_call(server, p0, p)) < 0) {
+ nfs_rpc_free(p0);
+ return status;
+ }
+ if (!(p = nfs_rpc_verify(p0)))
+ status = NFSERR_IO;
+ else if ((status = ntohl(*p++)) == NFS_OK) {
+ p = xdr_decode_fattr(p, fattr);
+ PRINTK("NFS reply getattr\n");
+ }
+ else {
+ if (!ruid && current->euid == 0 && current->uid != 0) {
+ ruid = 1;
+ goto retry;
+ }
+ PRINTK("NFS reply getattr failed = %d\n", status);
+ }
+ nfs_rpc_free(p0);
+ return -nfs_stat_to_errno(status);
+}
+
+int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_sattr *sattr, struct nfs_fattr *fattr)
+{
+ int *p, *p0;
+ int status;
+ int ruid = 0;
+
+ PRINTK("NFS call setattr\n");
+ if (!(p0 = nfs_rpc_alloc()))
+ return -EIO;
+retry:
+ p = nfs_rpc_header(p0, NFSPROC_SETATTR, ruid);
+ p = xdr_encode_fhandle(p, fhandle);
+ p = xdr_encode_sattr(p, sattr);
+ if ((status = nfs_rpc_call(server, p0, p)) < 0) {
+ nfs_rpc_free(p0);
+ return status;
+ }
+ if (!(p = nfs_rpc_verify(p0)))
+ status = NFSERR_IO;
+ else if ((status = ntohl(*p++)) == NFS_OK) {
+ p = xdr_decode_fattr(p, fattr);
+ PRINTK("NFS reply setattr\n");
+ }
+ else {
+ if (!ruid && current->euid == 0 && current->uid != 0) {
+ ruid = 1;
+ goto retry;
+ }
+ PRINTK("NFS reply setattr failed = %d\n", status);
+ }
+ nfs_rpc_free(p0);
+ return -nfs_stat_to_errno(status);
+}
+
+int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *name,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+ int *p, *p0;
+ int status;
+ int ruid = 0;
+
+ PRINTK("NFS call lookup %s\n", name);
+#ifdef NFS_PROC_DEBUG
+ if (!strcmp(name, "xyzzy"))
+ proc_debug = 1 - proc_debug;
+#endif
+ if (!(p0 = nfs_rpc_alloc()))
+ return -EIO;
+retry:
+ p = nfs_rpc_header(p0, NFSPROC_LOOKUP, ruid);
+ p = xdr_encode_fhandle(p, dir);
+ p = xdr_encode_string(p, name);
+ if ((status = nfs_rpc_call(server, p0, p)) < 0) {
+ nfs_rpc_free(p0);
+ return status;
+ }
+ if (!(p = nfs_rpc_verify(p0)))
+ status = NFSERR_IO;
+ else if ((status = ntohl(*p++)) == NFS_OK) {
+ p = xdr_decode_fhandle(p, fhandle);
+ p = xdr_decode_fattr(p, fattr);
+ PRINTK("NFS reply lookup\n");
+ }
+ else {
+ if (!ruid && current->euid == 0 && current->uid != 0) {
+ ruid = 1;
+ goto retry;
+ }
+ PRINTK("NFS reply lookup failed = %d\n", status);
+ }
+ nfs_rpc_free(p0);
+ return -nfs_stat_to_errno(status);
+}
+
+int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
+ char *res)
+{
+ int *p, *p0;
+ int status;
+ int ruid = 0;
+
+ PRINTK("NFS call readlink\n");
+ if (!(p0 = nfs_rpc_alloc()))
+ return -EIO;
+retry:
+ p = nfs_rpc_header(p0, NFSPROC_READLINK, ruid);
+ p = xdr_encode_fhandle(p, fhandle);
+ if ((status = nfs_rpc_call(server, p0, p)) < 0) {
+ nfs_rpc_free(p0);
+ return status;
+ }
+ if (!(p = nfs_rpc_verify(p0)))
+ status = NFSERR_IO;
+ else if ((status = ntohl(*p++)) == NFS_OK) {
+ if (!(p = xdr_decode_string(p, res, NFS_MAXPATHLEN))) {
+ printk("nfs_proc_readlink: giant pathname\n");
+ status = NFSERR_IO;
+ }
+ else
+ PRINTK("NFS reply readlink %s\n", res);
+ }
+ else {
+ if (!ruid && current->euid == 0 && current->uid != 0) {
+ ruid = 1;
+ goto retry;
+ }
+ PRINTK("NFS reply readlink failed = %d\n", status);
+ }
+ nfs_rpc_free(p0);
+ return -nfs_stat_to_errno(status);
+}
+
+int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
+ int offset, int count, char *data, struct nfs_fattr *fattr)
+{
+ int *p, *p0;
+ int status;
+ int ruid = 0;
+ int len = 0; /* = 0 is for gcc */
+
+ PRINTK("NFS call read %d @ %d\n", count, offset);
+ if (!(p0 = nfs_rpc_alloc()))
+ return -EIO;
+retry:
+ p = nfs_rpc_header(p0, NFSPROC_READ, ruid);
+ p = xdr_encode_fhandle(p, fhandle);
+ *p++ = htonl(offset);
+ *p++ = htonl(count);
+ *p++ = htonl(count); /* traditional, could be any value */
+ if ((status = nfs_rpc_call(server, p0, p)) < 0) {
+ nfs_rpc_free(p0);
+ return status;
+ }
+ if (!(p = nfs_rpc_verify(p0)))
+ status = NFSERR_IO;
+ else if ((status = ntohl(*p++)) == NFS_OK) {
+ p = xdr_decode_fattr(p, fattr);
+ if (!(p = xdr_decode_data(p, data, &len, count))) {
+ printk("nfs_proc_read: giant data size\n");
+ status = NFSERR_IO;
+ }
+ else
+ PRINTK("NFS reply read %d\n", len);
+ }
+ else {
+ if (!ruid && current->euid == 0 && current->uid != 0) {
+ ruid = 1;
+ goto retry;
+ }
+ PRINTK("NFS reply read failed = %d\n", status);
+ }
+ nfs_rpc_free(p0);
+ return (status == NFS_OK) ? len : -nfs_stat_to_errno(status);
+}
+
+int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
+ int offset, int count, char *data, struct nfs_fattr *fattr)
+{
+ int *p, *p0;
+ int status;
+ int ruid = 0;
+
+ PRINTK("NFS call write %d @ %d\n", count, offset);
+ if (!(p0 = nfs_rpc_alloc()))
+ return -EIO;
+retry:
+ p = nfs_rpc_header(p0, NFSPROC_WRITE, ruid);
+ p = xdr_encode_fhandle(p, fhandle);
+ *p++ = htonl(offset); /* traditional, could be any value */
+ *p++ = htonl(offset);
+ *p++ = htonl(count); /* traditional, could be any value */
+ p = xdr_encode_data(p, data, count);
+ if ((status = nfs_rpc_call(server, p0, p)) < 0) {
+ nfs_rpc_free(p0);
+ return status;
+ }
+ if (!(p = nfs_rpc_verify(p0)))
+ status = NFSERR_IO;
+ else if ((status = ntohl(*p++)) == NFS_OK) {
+ p = xdr_decode_fattr(p, fattr);
+ PRINTK("NFS reply write\n");
+ }
+ else {
+ if (!ruid && current->euid == 0 && current->uid != 0) {
+ ruid = 1;
+ goto retry;
+ }
+ PRINTK("NFS reply write failed = %d\n", status);
+ }
+ nfs_rpc_free(p0);
+ return -nfs_stat_to_errno(status);
+}
+
+int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name, struct nfs_sattr *sattr,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+ int *p, *p0;
+ int status;
+ int ruid = 0;
+
+ PRINTK("NFS call create %s\n", name);
+ if (!(p0 = nfs_rpc_alloc()))
+ return -EIO;
+retry:
+ p = nfs_rpc_header(p0, NFSPROC_CREATE, ruid);
+ p = xdr_encode_fhandle(p, dir);
+ p = xdr_encode_string(p, name);
+ p = xdr_encode_sattr(p, sattr);
+ if ((status = nfs_rpc_call(server, p0, p)) < 0) {
+ nfs_rpc_free(p0);
+ return status;
+ }
+ if (!(p = nfs_rpc_verify(p0)))
+ status = NFSERR_IO;
+ else if ((status = ntohl(*p++)) == NFS_OK) {
+ p = xdr_decode_fhandle(p, fhandle);
+ p = xdr_decode_fattr(p, fattr);
+ PRINTK("NFS reply create\n");
+ }
+ else {
+ if (!ruid && current->euid == 0 && current->uid != 0) {
+ ruid = 1;
+ goto retry;
+ }
+ PRINTK("NFS reply create failed = %d\n", status);
+ }
+ nfs_rpc_free(p0);
+ return -nfs_stat_to_errno(status);
+}
+
+int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *name)
+{
+ int *p, *p0;
+ int status;
+ int ruid = 0;
+
+ PRINTK("NFS call remove %s\n", name);
+ if (!(p0 = nfs_rpc_alloc()))
+ return -EIO;
+retry:
+ p = nfs_rpc_header(p0, NFSPROC_REMOVE, ruid);
+ p = xdr_encode_fhandle(p, dir);
+ p = xdr_encode_string(p, name);
+ if ((status = nfs_rpc_call(server, p0, p)) < 0) {
+ nfs_rpc_free(p0);
+ return status;
+ }
+ if (!(p = nfs_rpc_verify(p0)))
+ status = NFSERR_IO;
+ else if ((status = ntohl(*p++)) == NFS_OK) {
+ PRINTK("NFS reply remove\n");
+ }
+ else {
+ if (!ruid && current->euid == 0 && current->uid != 0) {
+ ruid = 1;
+ goto retry;
+ }
+ PRINTK("NFS reply remove failed = %d\n", status);
+ }
+ nfs_rpc_free(p0);
+ return -nfs_stat_to_errno(status);
+}
+
+int nfs_proc_rename(struct nfs_server *server,
+ struct nfs_fh *old_dir, const char *old_name,
+ struct nfs_fh *new_dir, const char *new_name)
+{
+ int *p, *p0;
+ int status;
+ int ruid = 0;
+
+ PRINTK("NFS call rename %s -> %s\n", old_name, new_name);
+ if (!(p0 = nfs_rpc_alloc()))
+ return -EIO;
+retry:
+ p = nfs_rpc_header(p0, NFSPROC_RENAME, ruid);
+ p = xdr_encode_fhandle(p, old_dir);
+ p = xdr_encode_string(p, old_name);
+ p = xdr_encode_fhandle(p, new_dir);
+ p = xdr_encode_string(p, new_name);
+ if ((status = nfs_rpc_call(server, p0, p)) < 0) {
+ nfs_rpc_free(p0);
+ return status;
+ }
+ if (!(p = nfs_rpc_verify(p0)))
+ status = NFSERR_IO;
+ else if ((status = ntohl(*p++)) == NFS_OK) {
+ PRINTK("NFS reply rename\n");
+ }
+ else {
+ if (!ruid && current->euid == 0 && current->uid != 0) {
+ ruid = 1;
+ goto retry;
+ }
+ PRINTK("NFS reply rename failed = %d\n", status);
+ }
+ nfs_rpc_free(p0);
+ return -nfs_stat_to_errno(status);
+}
+
+int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fh *dir, const char *name)
+{
+ int *p, *p0;
+ int status;
+ int ruid = 0;
+
+ PRINTK("NFS call link %s\n", name);
+ if (!(p0 = nfs_rpc_alloc()))
+ return -EIO;
+retry:
+ p = nfs_rpc_header(p0, NFSPROC_LINK, ruid);
+ p = xdr_encode_fhandle(p, fhandle);
+ p = xdr_encode_fhandle(p, dir);
+ p = xdr_encode_string(p, name);
+ if ((status = nfs_rpc_call(server, p0, p)) < 0) {
+ nfs_rpc_free(p0);
+ return status;
+ }
+ if (!(p = nfs_rpc_verify(p0)))
+ status = NFSERR_IO;
+ else if ((status = ntohl(*p++)) == NFS_OK) {
+ PRINTK("NFS reply link\n");
+ }
+ else {
+ if (!ruid && current->euid == 0 && current->uid != 0) {
+ ruid = 1;
+ goto retry;
+ }
+ PRINTK("NFS reply link failed = %d\n", status);
+ }
+ nfs_rpc_free(p0);
+ return -nfs_stat_to_errno(status);
+}
+
+int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name, const char *path, struct nfs_sattr *sattr)
+{
+ int *p, *p0;
+ int status;
+ int ruid = 0;
+
+ PRINTK("NFS call symlink %s -> %s\n", name, path);
+ if (!(p0 = nfs_rpc_alloc()))
+ return -EIO;
+retry:
+ p = nfs_rpc_header(p0, NFSPROC_SYMLINK, ruid);
+ p = xdr_encode_fhandle(p, dir);
+ p = xdr_encode_string(p, name);
+ p = xdr_encode_string(p, path);
+ p = xdr_encode_sattr(p, sattr);
+ if ((status = nfs_rpc_call(server, p0, p)) < 0) {
+ nfs_rpc_free(p0);
+ return status;
+ }
+ if (!(p = nfs_rpc_verify(p0)))
+ status = NFSERR_IO;
+ else if ((status = ntohl(*p++)) == NFS_OK) {
+ PRINTK("NFS reply symlink\n");
+ }
+ else {
+ if (!ruid && current->euid == 0 && current->uid != 0) {
+ ruid = 1;
+ goto retry;
+ }
+ PRINTK("NFS reply symlink failed = %d\n", status);
+ }
+ nfs_rpc_free(p0);
+ return -nfs_stat_to_errno(status);
+}
+
+int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name, struct nfs_sattr *sattr,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+ int *p, *p0;
+ int status;
+ int ruid = 0;
+
+ PRINTK("NFS call mkdir %s\n", name);
+ if (!(p0 = nfs_rpc_alloc()))
+ return -EIO;
+retry:
+ p = nfs_rpc_header(p0, NFSPROC_MKDIR, ruid);
+ p = xdr_encode_fhandle(p, dir);
+ p = xdr_encode_string(p, name);
+ p = xdr_encode_sattr(p, sattr);
+ if ((status = nfs_rpc_call(server, p0, p)) < 0) {
+ nfs_rpc_free(p0);
+ return status;
+ }
+ if (!(p = nfs_rpc_verify(p0)))
+ status = NFSERR_IO;
+ else if ((status = ntohl(*p++)) == NFS_OK) {
+ p = xdr_decode_fhandle(p, fhandle);
+ p = xdr_decode_fattr(p, fattr);
+ PRINTK("NFS reply mkdir\n");
+ }
+ else {
+ if (!ruid && current->euid == 0 && current->uid != 0) {
+ ruid = 1;
+ goto retry;
+ }
+ PRINTK("NFS reply mkdir failed = %d\n", status);
+ }
+ nfs_rpc_free(p0);
+ return -nfs_stat_to_errno(status);
+}
+
+int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name)
+{
+ int *p, *p0;
+ int status;
+ int ruid = 0;
+
+ PRINTK("NFS call rmdir %s\n", name);
+ if (!(p0 = nfs_rpc_alloc()))
+ return -EIO;
+retry:
+ p = nfs_rpc_header(p0, NFSPROC_RMDIR, ruid);
+ p = xdr_encode_fhandle(p, dir);
+ p = xdr_encode_string(p, name);
+ if ((status = nfs_rpc_call(server, p0, p)) < 0) {
+ nfs_rpc_free(p0);
+ return status;
+ }
+ if (!(p = nfs_rpc_verify(p0)))
+ status = NFSERR_IO;
+ else if ((status = ntohl(*p++)) == NFS_OK) {
+ PRINTK("NFS reply rmdir\n");
+ }
+ else {
+ if (!ruid && current->euid == 0 && current->uid != 0) {
+ ruid = 1;
+ goto retry;
+ }
+ PRINTK("NFS reply rmdir failed = %d\n", status);
+ }
+ nfs_rpc_free(p0);
+ return -nfs_stat_to_errno(status);
+}
+
+int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
+ int cookie, int count, struct nfs_entry *entry)
+{
+ int *p, *p0;
+ int status;
+ int ruid = 0;
+ int i = 0; /* = 0 is for gcc */
+ int size;
+ int eof;
+
+ PRINTK("NFS call readdir %d @ %d\n", count, cookie);
+ size = server->rsize;
+ if (!(p0 = nfs_rpc_alloc()))
+ return -EIO;
+retry:
+ p = nfs_rpc_header(p0, NFSPROC_READDIR, ruid);
+ p = xdr_encode_fhandle(p, fhandle);
+ *p++ = htonl(cookie);
+ *p++ = htonl(size);
+ if ((status = nfs_rpc_call(server, p0, p)) < 0) {
+ nfs_rpc_free(p0);
+ return status;
+ }
+ if (!(p = nfs_rpc_verify(p0)))
+ status = NFSERR_IO;
+ else if ((status = ntohl(*p++)) == NFS_OK) {
+ for (i = 0; i < count && *p++; i++) {
+ if (!(p = xdr_decode_entry(p, entry++)))
+ break;
+ }
+ if (!p) {
+ printk("nfs_proc_readdir: giant filename\n");
+ status = NFSERR_IO;
+ }
+ else {
+ eof = (i == count && !*p++ && *p++)
+ || (i < count && *p++);
+ if (eof && i)
+ entry[-1].eof = 1;
+ PRINTK("NFS reply readdir %d %s\n", i,
+ eof ? "eof" : "");
+ }
+ }
+ else {
+ if (!ruid && current->euid == 0 && current->uid != 0) {
+ ruid = 1;
+ goto retry;
+ }
+ PRINTK("NFS reply readdir failed = %d\n", status);
+ }
+ nfs_rpc_free(p0);
+ return (status == NFS_OK) ? i : -nfs_stat_to_errno(status);
+}
+
+int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fsinfo *res)
+{
+ int *p, *p0;
+ int status;
+ int ruid = 0;
+
+ PRINTK("NFS call statfs\n");
+ if (!(p0 = nfs_rpc_alloc()))
+ return -EIO;
+retry:
+ p = nfs_rpc_header(p0, NFSPROC_STATFS, ruid);
+ p = xdr_encode_fhandle(p, fhandle);
+ if ((status = nfs_rpc_call(server, p0, p)) < 0) {
+ nfs_rpc_free(p0);
+ return status;
+ }
+ if (!(p = nfs_rpc_verify(p0)))
+ status = NFSERR_IO;
+ else if ((status = ntohl(*p++)) == NFS_OK) {
+ p = xdr_decode_fsinfo(p, res);
+ PRINTK("NFS reply statfs\n");
+ }
+ else {
+ if (!ruid && current->euid == 0 && current->uid != 0) {
+ ruid = 1;
+ goto retry;
+ }
+ PRINTK("NFS reply statfs failed = %d\n", status);
+ }
+ nfs_rpc_free(p0);
+ return -nfs_stat_to_errno(status);
+}
+
+/*
+ * Here are a few RPC-assist functions.
+ */
+
+static int *nfs_rpc_header(int *p, int procedure, int ruid)
+{
+ int *p1, *p2;
+ int i;
+ static int xid = 0;
+ unsigned char *sys = (unsigned char *) system_utsname.nodename;
+
+ if (xid == 0) {
+ xid = CURRENT_TIME;
+ xid ^= (sys[3]<<24) | (sys[2]<<16) | (sys[1]<<8) | sys[0];
+ }
+ *p++ = htonl(++xid);
+ *p++ = htonl(RPC_CALL);
+ *p++ = htonl(RPC_VERSION);
+ *p++ = htonl(NFS_PROGRAM);
+ *p++ = htonl(NFS_VERSION);
+ *p++ = htonl(procedure);
+ *p++ = htonl(RPC_AUTH_UNIX);
+ p1 = p++;
+ *p++ = htonl(CURRENT_TIME); /* traditional, could be anything */
+ p = xdr_encode_string(p, (char *) sys);
+ *p++ = htonl(ruid ? current->uid : current->euid);
+ *p++ = htonl(current->egid);
+ p2 = p++;
+ for (i = 0; i < 16 && i < NGROUPS && current->groups[i] != NOGROUP; i++)
+ *p++ = htonl(current->groups[i]);
+ *p2 = htonl(i);
+ *p1 = htonl((p - (p1 + 1)) << 2);
+ *p++ = htonl(RPC_AUTH_NULL);
+ *p++ = htonl(0);
+ return p;
+}
+
+static int *nfs_rpc_verify(int *p)
+{
+ unsigned int n;
+
+ p++;
+ if ((n = ntohl(*p++)) != RPC_REPLY) {
+ printk("nfs_rpc_verify: not an RPC reply: %d\n", n);
+ return NULL;
+ }
+ if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
+ printk("nfs_rpc_verify: RPC call rejected: %d\n", n);
+ return NULL;
+ }
+ switch (n = ntohl(*p++)) {
+ case RPC_AUTH_NULL: case RPC_AUTH_UNIX: case RPC_AUTH_SHORT:
+ break;
+ default:
+ printk("nfs_rpc_verify: bad RPC authentication type: %d\n", n);
+ return NULL;
+ }
+ if ((n = ntohl(*p++)) > 400) {
+ printk("nfs_rpc_verify: giant auth size\n");
+ return NULL;
+ }
+ p += (n + 3) >> 2;
+ if ((n = ntohl(*p++)) != RPC_SUCCESS) {
+ printk("nfs_rpc_verify: RPC call failed: %d\n", n);
+ return NULL;
+ }
+ return p;
+}
+
+/*
+ * We need to translate between nfs status return values and
+ * the local errno values which may not be the same.
+ */
+
+#ifndef EDQUOT
+#define EDQUOT ENOSPC
+#endif
+
+static struct {
+ int stat;
+ int errno;
+} nfs_errtbl[] = {
+ { NFS_OK, 0 },
+ { NFSERR_PERM, EPERM },
+ { NFSERR_NOENT, ENOENT },
+ { NFSERR_IO, EIO },
+ { NFSERR_NXIO, ENXIO },
+ { NFSERR_ACCES, EACCES },
+ { NFSERR_EXIST, EEXIST },
+ { NFSERR_NODEV, ENODEV },
+ { NFSERR_NOTDIR, ENOTDIR },
+ { NFSERR_ISDIR, EISDIR },
+ { NFSERR_INVAL, EINVAL },
+ { NFSERR_FBIG, EFBIG },
+ { NFSERR_NOSPC, ENOSPC },
+ { NFSERR_ROFS, EROFS },
+ { NFSERR_NAMETOOLONG, ENAMETOOLONG },
+ { NFSERR_NOTEMPTY, ENOTEMPTY },
+ { NFSERR_DQUOT, EDQUOT },
+ { NFSERR_STALE, ESTALE },
+#ifdef EWFLUSH
+ { NFSERR_WFLUSH, EWFLUSH },
+#endif
+ { -1, EIO }
+};
+
+static int nfs_stat_to_errno(int stat)
+{
+ int i;
+
+ for (i = 0; nfs_errtbl[i].stat != -1; i++) {
+ if (nfs_errtbl[i].stat == stat)
+ return nfs_errtbl[i].errno;
+ }
+ printk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
+ return nfs_errtbl[i].errno;
+}
+
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/fs/nfs/sock.c linux-0.9pl4/fs/nfs/sock.c
--- linux-0.9pl3/fs/nfs/sock.c Wed Dec 31 19:00:00 1969
+++ linux-0.9pl4/fs/nfs/sock.c Tue Mar 1 01:03:41 1994
@@ -0,0 +1,185 @@
+/*
+ * linux/fs/nfs/sock.c
+ *
+ * Copyright (C) 1992, 1993 Rick Sladkey
+ *
+ * low-level nfs remote procedure call interface
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/nfs_fs.h>
+#include <linux/errno.h>
+#include <linux/socket.h>
+#include <linux/fcntl.h>
+#include <asm/segment.h>
+#include <linux/in.h>
+#include <linux/net.h>
+
+
+extern struct socket *socki_lookup(struct inode *inode);
+
+#define _S(nr) (1<<((nr)-1))
+
+/*
+ * We violate some modularity principles here by poking around
+ * in some socket internals. Besides having to call socket
+ * functions from kernel-space instead of user space, the socket
+ * interface does not lend itself well to being cleanly called
+ * without a file descriptor. Since the nfs calls can run on
+ * behalf of any process, the superblock maintains a file pointer
+ * to the server socket.
+ */
+
+static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end)
+{
+ struct file *file;
+ struct inode *inode;
+ struct socket *sock;
+ unsigned short fs;
+ int result;
+ int xid;
+ int len;
+ select_table wait_table;
+ struct select_table_entry entry;
+ int (*select) (struct inode *, struct file *, int, select_table *);
+ int init_timeout, max_timeout;
+ int timeout;
+ int retrans;
+ int major_timeout_seen;
+ char *server_name;
+ int n;
+ int addrlen;
+ unsigned long old_mask;
+
+ xid = start[0];
+ len = ((char *) end) - ((char *) start);
+ file = server->file;
+ inode = file->f_inode;
+ select = file->f_op->select;
+ sock = socki_lookup(inode);
+ if (!sock) {
+ printk("nfs_rpc_call: socki_lookup failed\n");
+ return -EBADF;
+ }
+ init_timeout = server->timeo;
+ max_timeout = NFS_MAX_RPC_TIMEOUT*HZ/10;
+ retrans = server->retrans;
+ major_timeout_seen = 0;
+ server_name = server->hostname;
+ old_mask = current->blocked;
+ current->blocked |= ~(_S(SIGKILL)
+#if 0
+ | _S(SIGSTOP)
+#endif
+ | ((server->flags & NFS_MOUNT_INTR)
+ ? ((current->sigaction[SIGINT - 1].sa_handler == SIG_DFL
+ ? _S(SIGINT) : 0)
+ | (current->sigaction[SIGQUIT - 1].sa_handler == SIG_DFL
+ ? _S(SIGQUIT) : 0))
+ : 0));
+ fs = get_fs();
+ set_fs(get_ds());
+ for (n = 0, timeout = init_timeout; ; n++, timeout <<= 1) {
+ result = sock->ops->send(sock, (void *) start, len, 0, 0);
+ if (result < 0) {
+ printk("nfs_rpc_call: send error = %d\n", result);
+ break;
+ }
+ re_select:
+ wait_table.nr = 0;
+ wait_table.entry = &entry;
+ current->state = TASK_INTERRUPTIBLE;
+ if (!select(inode, file, SEL_IN, &wait_table)
+ && !select(inode, file, SEL_IN, NULL)) {
+ if (timeout > max_timeout)
+ timeout = max_timeout;
+ current->timeout = jiffies + timeout;
+ schedule();
+ remove_wait_queue(entry.wait_address, &entry.wait);
+ current->state = TASK_RUNNING;
+ if (current->signal & ~current->blocked) {
+ current->timeout = 0;
+ result = -ERESTARTSYS;
+ break;
+ }
+ if (!current->timeout) {
+ if (n < retrans)
+ continue;
+ if (server->flags & NFS_MOUNT_SOFT) {
+ printk("NFS server %s not responding, "
+ "timed out\n", server_name);
+ result = -EIO;
+ break;
+ }
+ n = 0;
+ timeout = init_timeout;
+ init_timeout <<= 1;
+ if (!major_timeout_seen) {
+ printk("NFS server %s not responding, "
+ "still trying\n", server_name);
+ }
+ major_timeout_seen = 1;
+ continue;
+ }
+ else
+ current->timeout = 0;
+ }
+ else if (wait_table.nr)
+ remove_wait_queue(entry.wait_address, &entry.wait);
+ current->state = TASK_RUNNING;
+ addrlen = 0;
+ result = sock->ops->recvfrom(sock, (void *) start, PAGE_SIZE, 1, 0,
+ NULL, &addrlen);
+ if (result < 0) {
+ if (result == -EAGAIN) {
+#if 0
+ printk("nfs_rpc_call: bad select ready\n");
+#endif
+ goto re_select;
+ }
+ if (result == -ECONNREFUSED) {
+#if 0
+ printk("nfs_rpc_call: server playing coy\n");
+#endif
+ goto re_select;
+ }
+ if (result != -ERESTARTSYS) {
+ printk("nfs_rpc_call: recv error = %d\n",
+ -result);
+ }
+ break;
+ }
+ if (*start == xid) {
+ if (major_timeout_seen)
+ printk("NFS server %s OK\n", server_name);
+ break;
+ }
+#if 0
+ printk("nfs_rpc_call: XID mismatch\n");
+#endif
+ }
+ current->blocked = old_mask;
+ set_fs(fs);
+ return result;
+}
+
+/*
+ * For now we lock out other simulaneous nfs calls for the same filesytem
+ * because we are single-threaded and don't want to get mismatched
+ * RPC replies.
+ */
+
+int nfs_rpc_call(struct nfs_server *server, int *start, int *end)
+{
+ int result;
+
+ while (server->lock)
+ sleep_on(&server->wait);
+ server->lock = 1;
+ result = do_nfs_rpc_call(server, start, end);
+ server->lock = 0;
+ wake_up(&server->wait);
+ return result;
+}
+
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/fs/nfs/symlink.c linux-0.9pl4/fs/nfs/symlink.c
--- linux-0.9pl3/fs/nfs/symlink.c Wed Dec 31 19:00:00 1969
+++ linux-0.9pl4/fs/nfs/symlink.c Wed Dec 1 07:44:15 1993
@@ -0,0 +1,108 @@
+/*
+ * linux/fs/nfs/symlink.c
+ *
+ * Copyright (C) 1992 Rick Sladkey
+ *
+ * nfs symlink handling code
+ */
+
+#include <asm/segment.h>
+
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/nfs_fs.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+
+static int nfs_readlink(struct inode *, char *, int);
+static int nfs_follow_link(struct inode *, struct inode *, int, int,
+ struct inode **);
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations nfs_symlink_inode_operations = {
+ NULL, /* no file-operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ nfs_readlink, /* readlink */
+ nfs_follow_link, /* follow_link */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+static int nfs_follow_link(struct inode *dir, struct inode *inode,
+ int flag, int mode, struct inode **res_inode)
+{
+ int error;
+ char *res;
+
+ *res_inode = NULL;
+ if (!dir) {
+ dir = current->root;
+ dir->i_count++;
+ }
+ if (!inode) {
+ iput(dir);
+ return -ENOENT;
+ }
+ if (!S_ISLNK(inode->i_mode)) {
+ iput(dir);
+ *res_inode = inode;
+ return 0;
+ }
+ if (current->link_count > 5) {
+ iput(inode);
+ iput(dir);
+ return -ELOOP;
+ }
+ res = (char *) kmalloc(NFS_MAXPATHLEN + 1, GFP_KERNEL);
+ error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), res);
+ if (error) {
+ iput(inode);
+ iput(dir);
+ kfree_s(res, NFS_MAXPATHLEN + 1);
+ return error;
+ }
+ iput(inode);
+ current->link_count++;
+ error = open_namei(res, flag, mode, res_inode, dir);
+ current->link_count--;
+ kfree_s(res, NFS_MAXPATHLEN + 1);
+ return error;
+}
+
+static int nfs_readlink(struct inode *inode, char *buffer, int buflen)
+{
+ int i;
+ char c;
+ int error;
+ char *res;
+
+ if (!S_ISLNK(inode->i_mode)) {
+ iput(inode);
+ return -EINVAL;
+ }
+ if (buflen > NFS_MAXPATHLEN)
+ buflen = NFS_MAXPATHLEN;
+ res = (char *) kmalloc(buflen + 1, GFP_KERNEL);
+ error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), res);
+ iput(inode);
+ if (error) {
+ kfree_s(res, buflen + 1);
+ return error;
+ }
+ for (i = 0; i < buflen && (c = res[i]); i++)
+ put_fs_byte(c,buffer++);
+ kfree_s(res, buflen + 1);
+ return i;
+}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/include/asm/segment.h linux-0.9pl4/include/asm/segment.h
--- linux-0.9pl3/include/asm/segment.h Fri Aug 19 17:05:08 1994
+++ linux-0.9pl4/include/asm/segment.h Mon Oct 10 16:48:26 1994
@@ -83,20 +83,19 @@
static inline void __constant_memcpy_tofs(void * to, const void * from, unsigned long n)
{
- switch (n) {
- case 0:
+ if (n == 0) {
return;
- case 1:
+ } else if (n == 1) {
put_user_byte(*(const char *) from, (char *) to);
return;
- case 2:
+ } else if (n == 2) {
put_user_word(*(const short *) from, (short *) to);
return;
- case 3:
+ } else if (n == 3) {
put_user_word(*(const short *) from, (short *) to);
put_user_byte(*(2+(const char *) from), 2+(char *) to);
return;
- case 4:
+ } else if (n == 4) {
put_user_long(*(const int *) from, (int *) to);
return;
}
@@ -150,20 +149,19 @@
static inline void __constant_memcpy_fromfs(void * to, const void * from, unsigned long n)
{
- switch (n) {
- case 0:
+ if (n == 0) {
return;
- case 1:
+ } else if (n == 1) {
*(char *)to = get_user_byte((const char *) from);
return;
- case 2:
+ } else if (n == 2) {
*(short *)to = get_user_word((const short *) from);
return;
- case 3:
+ } else if (n == 3) {
*(short *) to = get_user_word((const short *) from);
*(2+(char *) to) = get_user_byte(2+(const char *) from);
return;
- case 4:
+ } else if (n == 4) {
*(int *) to = get_user_long((const int *) from);
return;
}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/include/linux/amihdreg.h linux-0.9pl4/include/linux/amihdreg.h
--- linux-0.9pl3/include/linux/amihdreg.h Sun Aug 14 10:29:35 1994
+++ linux-0.9pl4/include/linux/amihdreg.h Thu Nov 24 20:52:38 1994
@@ -10,20 +10,23 @@
#define IDE_DISABLE_IRQ 0x02
#define IDE_ENABLE_IRQ 0x00
-/* Hd controller regs. Ref: Disassembling scsi.device */
-#define HD_DATA 0xdd2020 /* _CTL when writing */
-#define HD_ERROR 0xdd2026 /* see err-bits */
-#define HD_NSECTOR 0xdd202a /* nr of sectors to read/write */
-#define HD_SECTOR 0xdd202e /* starting sector */
-#define HD_LCYL 0xdd2032 /* starting cylinder */
-#define HD_HCYL 0xdd2036 /* high byte of starting cyl */
-#define HD_CURRENT 0xdd203a /* 101dhhhh , d=drive, hhhh=head */
-#define HD_STATUS 0xdd203e /* see status-bits */
-#define HD_PRECOMP HD_ERROR /* same io address, read=error, write=precomp */
-#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */
+/* Bases of the hard drive controller */
+#define HD_BASE_A4000 0xdd2020
+#define HD_BASE_A1200 0xda0000
-#define HD_IRQ_TEST 0xdd3020 /* MSB = 1, Harddisk is source of interrupt */
-#define HD_CMD 0xdd303a
+/* Offsets from one of the above bases */
+#define HD_ERROR (0x06) /* see err-bits */
+#define HD_NSECTOR (0x0a) /* nr of sectors to read/write */
+#define HD_SECTOR (0x0e) /* starting sector */
+#define HD_LCYL (0x12) /* starting cylinder */
+#define HD_HCYL (0x16) /* high byte of starting cyl */
+#define HD_CURRENT (0x1a) /* 101dhhhh , d=drive, hhhh=head */
+#define HD_STATUS (0x1e) /* see status-bits */
+#define HD_CMD (0x101a)
+
+/* These are at different offsets from the base */
+#define HD_A4000_IRQ (0xdd3020) /* MSB = 1, Harddisk is source of interrupt */
+#define HD_A1200_IRQ (0xda9000) /* MSB = 1, Harddisk is source of interrupt */
/* Bits of HD_STATUS */
#define ERR_STAT 0x01
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/include/linux/atafdreg.h linux-0.9pl4/include/linux/atafdreg.h
--- linux-0.9pl3/include/linux/atafdreg.h Sun Aug 14 10:29:37 1994
+++ linux-0.9pl4/include/linux/atafdreg.h Mon Nov 7 22:33:51 1994
@@ -5,10 +5,22 @@
** WD1772 stuff
*/
-#define FDCSELREG_STP (0x80)
-#define FDCSELREG_TRA (0x82)
-#define FDCSELREG_SEC (0x84)
-#define FDCSELREG_DTA (0x86)
+/* register codes */
+
+#define FDCSELREG_STP (0x80) /* command/status register */
+#define FDCSELREG_TRA (0x82) /* track register */
+#define FDCSELREG_SEC (0x84) /* sector register */
+#define FDCSELREG_DTA (0x86) /* data register */
+
+/* register names for FDC_READ/WRITE macros */
+
+#define FDCREG_CMD 0
+#define FDCREG_STATUS 0
+#define FDCREG_TRACK 2
+#define FDCREG_SECTOR 4
+#define FDCREG_DATA 6
+
+/* command opcodes */
#define FDCCMD_RESTORE (0x00) /* - */
#define FDCCMD_SEEK (0x10) /* | */
@@ -20,26 +32,35 @@
#define FDCCMD_RDADR (0xc0) /* - */
#define FDCCMD_RDTRA (0xe0) /* | TYP 3 Commands */
#define FDCCMD_WRTRA (0xf0) /* - */
-#define FDCCMD_FORCI (0xc0) /* - TYP 4 Command */
+#define FDCCMD_FORCI (0xd0) /* - TYP 4 Command */
+
+/* command modifier bits */
-#define FDCCMDADD_SR6 (0x00)
+#define FDCCMDADD_SR6 (0x00) /* step rate settings */
#define FDCCMDADD_SR12 (0x01)
#define FDCCMDADD_SR2 (0x02)
#define FDCCMDADD_SR3 (0x03)
-
-#define FDCCMDADD_V (0x04)
-
-#define FDCCMDADD_H (0x08)
-
-#define FDCCMDADD_U (0x10)
-
-#define FDCCMDADD_M (0x10)
-
-#define FDCCMDADD_E (0x04)
-
-#define FDCCMDADD_P (0x02)
-
-#define FDCCMDADD_A0 (0x01)
+#define FDCCMDADD_V (0x04) /* verify */
+#define FDCCMDADD_H (0x08) /* wait for spin-up */
+#define FDCCMDADD_U (0x10) /* update track register */
+#define FDCCMDADD_M (0x10) /* multiple sector access */
+#define FDCCMDADD_E (0x04) /* head settling flag */
+#define FDCCMDADD_P (0x02) /* precompensation */
+#define FDCCMDADD_A0 (0x01) /* DAM flag */
+
+/* status register bits */
+
+#define FDCSTAT_MOTORON (0x80) /* motor on */
+#define FDCSTAT_WPROT (0x40) /* write protected (FDCCMD_WR*) */
+#define FDCSTAT_SPINUP (0x20) /* motor speed stable (Type I) */
+#define FDCSTAT_DELDAM (0x20) /* sector has deleted DAM (Type II+III) */
+#define FDCSTAT_RECNF (0x10) /* record not found */
+#define FDCSTAT_CRC (0x08) /* CRC error */
+#define FDCSTAT_TR00 (0x04) /* Track 00 flag (Type I) */
+#define FDCSTAT_LOST (0x04) /* Lost Data (Type II+III) */
+#define FDCSTAT_IDX (0x02) /* Index status (Type I) */
+#define FDCSTAT_DRQ (0x02) /* DRQ status (Type II+III) */
+#define FDCSTAT_BUSY (0x01) /* FDC is busy */
/* PSG Port A Bit Nr 0 .. Side Sel .. 0 -> Side 1 1 -> Side 2 */
@@ -47,25 +68,12 @@
#define DSKDRVNONE (0x06)
#define DSKDRV0 (0x02)
-#define DSKDRV1 (0x02)
-
+#define DSKDRV1 (0x04)
-/*
-** Misc
-*/
-
-#define MFM_SYNC 0x4489 /* standard MFM sync value */
-
-/* Values for FD_COMMAND */
-#define FD_RECALIBRATE 0x07 /* move to track 0 */
-#define FD_SEEK 0x0F /* seek track */
-#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */
-#define FD_WRITE 0xC5 /* write with MT, MFM */
-#define FD_SENSEI 0x08 /* Sense Interrupt Status */
-#define FD_SPECIFY 0x03 /* specify HUT etc */
-#define FD_FORMAT 0x4D /* format one track */
-#define FD_VERSION 0x10 /* get version code */
-#define FD_CONFIGURE 0x13 /* configure FIFO operation */
-#define FD_PERPENDICULAR 0x12 /* perpendicular r/w mode */
+/* step rates */
+#define FDCSTEP_6 0x00
+#define FDCSTEP_12 0x01
+#define FDCSTEP_2 0x02
+#define FDCSTEP_3 0x03
#endif
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/include/linux/atari_stdma.h linux-0.9pl4/include/linux/atari_stdma.h
--- linux-0.9pl3/include/linux/atari_stdma.h Sun Aug 14 10:29:37 1994
+++ linux-0.9pl4/include/linux/atari_stdma.h Mon Nov 7 22:33:52 1994
@@ -11,6 +11,8 @@
void stdma_lock( isrfunc isr, void *data );
void stdma_release( void );
int stdma_others_waiting( void );
+int stdma_islocked( void );
+void *stdma_locked_by( void );
void stdma_init( void );
/************************* End of Prototypes **************************/
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/include/linux/atarihw.h linux-0.9pl4/include/linux/atarihw.h
--- linux-0.9pl3/include/linux/atarihw.h Sun Aug 14 10:29:37 1994
+++ linux-0.9pl4/include/linux/atarihw.h Mon Nov 7 22:33:52 1994
@@ -20,7 +20,11 @@
/* Memory used for screen ram and stdma buffers */
void atari_stram_init (void);
+#if 0
void *atari_stram_alloc (long size);
+#else
+void *atari_stram_alloc (long size, unsigned long *start_mem );
+#endif
void atari_stram_free (void *);
/*
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/include/linux/bootinfo.h linux-0.9pl4/include/linux/bootinfo.h
--- linux-0.9pl3/include/linux/bootinfo.h Sun Aug 14 10:29:16 1994
+++ linux-0.9pl4/include/linux/bootinfo.h Mon Nov 7 22:34:38 1994
@@ -62,8 +62,6 @@
struct bi_Atari {
AtariModel model;
- unsigned long stram_start; /* Start of unmapped ST-RAM */
- unsigned long stram_size; /* Size of unmapped ST-RAM */
};
/*
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/include/linux/config.h linux-0.9pl4/include/linux/config.h
--- linux-0.9pl3/include/linux/config.h Sun Aug 14 10:29:15 1994
+++ linux-0.9pl4/include/linux/config.h Mon Oct 10 16:48:27 1994
@@ -15,7 +15,7 @@
* Defines for what uname() should return
*/
#ifndef UTS_SYSNAME
-#define UTS_SYSNAME "Linux/68k"
+#define UTS_SYSNAME "Linux"
#endif
#ifndef UTS_NODENAME
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/include/linux/console.h linux-0.9pl4/include/linux/console.h
--- linux-0.9pl3/include/linux/console.h Sun Aug 14 10:29:14 1994
+++ linux-0.9pl4/include/linux/console.h Mon Oct 24 22:27:10 1994
@@ -25,11 +25,14 @@
unsigned char vc_s_color; /* Saved foreground & background */
unsigned char vc_ulcolor; /* Colour for underline mode */
unsigned char vc_halfcolor; /* Colour for half intensity mode */
+ unsigned short *vc_pos;
unsigned long vc_x,vc_y;
unsigned long vc_top,vc_bottom;
unsigned long vc_rows,vc_cols;
+ unsigned long vc_size_row;
unsigned long vc_state;
unsigned long vc_npar,vc_par[NPAR];
+ unsigned short *vc_video_mem_start;
unsigned long vc_saved_x;
unsigned long vc_saved_y;
/* mode flags */
@@ -52,6 +55,7 @@
/* misc */
unsigned long vc_ques : 1;
unsigned long vc_need_wrap : 1;
+ unsigned long vc_can_do_color : 1;
unsigned long vc_tab_stop[5]; /* Tab stops. 160 columns. */
unsigned char * vc_translate;
unsigned char * vc_G0_charset;
@@ -71,11 +75,11 @@
/* DPC: 1994-04-13 !!! con_putcs is new entry !!! */
struct consw {
- long (*con_init)(struct condata *, long);
+ long (*con_init)(struct condata *, long, char **);
int (*con_deinit)(struct condata *);
int (*con_clear)(struct condata *, int, int, int, int);
- int (*con_putc)(struct condata *, int, int, int, int);
- int (*con_putcs)(struct condata *, const char *, int, int, int, int);
+ int (*con_putc)(struct condata *, int, int, int);
+ int (*con_putcs)(struct condata *, const char *, int, int, int);
int (*con_cursor)(struct condata *, int);
int (*con_scroll)(struct condata *, int, int, int, int);
int (*con_bmove)(struct condata *, int, int, int, int, int, int);
@@ -88,12 +92,6 @@
/* flag bits */
#define CON_INITED (1)
-
-/* definitions for draw mode */
-#define DM_CLEAR (1)
-#define DM_COPY (2)
-#define DM_XOR (3)
-#define DM_INVERSE (4)
/* scroll */
#define SM_UP (1)
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/include/linux/kd.h linux-0.9pl4/include/linux/kd.h
--- linux-0.9pl3/include/linux/kd.h Sun Aug 14 10:29:15 1994
+++ linux-0.9pl4/include/linux/kd.h Mon Nov 7 22:36:01 1994
@@ -212,4 +212,5 @@
/* note: 0x4B60 and 0x4B61 used above for GIO_FONT and PIO_FONT
0x4B62 and 0x4B63 used above for KDGKBMETA and KDSKBMETA */
+#define GET_SCRADDR 0x4b70 /* get the start of screen mem */
#endif /* _LINUX_KD_H */
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/include/linux/keyboard.h linux-0.9pl4/include/linux/keyboard.h
--- linux-0.9pl3/include/linux/keyboard.h Sun Aug 14 10:29:33 1994
+++ linux-0.9pl4/include/linux/keyboard.h Thu Nov 24 21:21:52 1994
@@ -18,14 +18,18 @@
#define NR_KEYS 128
#define NR_KEYMAPS 16
+#ifdef __KERNEL__
extern const int NR_TYPES;
extern const int max_vals[];
extern unsigned short (*key_map)[NR_KEYS];
+#endif
#define NR_FUNC 36
#define FUNC_BUFSIZE 512
+#ifdef __KERNEL__
extern char func_buf[FUNC_BUFSIZE];
extern char *func_table[NR_FUNC];
+#endif
#define KT_LATIN 0 /* we depend on this being zero */
#define KT_LETTER 11 /* symbol that can be acted upon by CapsLock */
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/include/linux/major.h linux-0.9pl4/include/linux/major.h
--- linux-0.9pl3/include/linux/major.h Sun Aug 14 10:29:14 1994
+++ linux-0.9pl4/include/linux/major.h Mon Nov 7 22:36:52 1994
@@ -45,6 +45,7 @@
* 25 - matsushita cdrom minors 0..3
* 26 -
* 27 - qic117 tape
+ * 28 - acsi disk
*/
#define UNNAMED_MAJOR 0
@@ -73,6 +74,7 @@
#define CDU535_CDROM_MAJOR 24
#define MATSUSHITA_CDROM_MAJOR 25
#define QIC117_TAPE_MAJOR 27
+#define ACSI_MAJOR 28
/*
* Tests for SCSI devices.
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/include/linux/mm.h linux-0.9pl4/include/linux/mm.h
--- linux-0.9pl3/include/linux/mm.h Sun Aug 28 17:16:17 1994
+++ linux-0.9pl4/include/linux/mm.h Mon Nov 21 18:34:17 1994
@@ -19,6 +19,7 @@
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/kernel.h>
+#include <asm/segment.h>
#define VERIFY_READ 0
#define VERIFY_WRITE 1
@@ -33,10 +34,12 @@
if (size > TASK_SIZE - (unsigned long) addr)
return -EFAULT;
#elif defined(__mc68000__)
- if (current->pid != 1 && TASK_SIZE <= (unsigned long) addr)
+ if (current->pid != 1 && get_fs () != get_ds ()) {
+ if (TASK_SIZE <= (unsigned long) addr)
return -EFAULT;
- if (current->pid != 1 && size > TASK_SIZE - (unsigned long) addr)
+ if (size > TASK_SIZE - (unsigned long) addr)
return -EFAULT;
+ }
#endif
if (wp_works_ok || type == VERIFY_READ || !size)
return 0;
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/include/linux/nfs_fs.h linux-0.9pl4/include/linux/nfs_fs.h
--- linux-0.9pl3/include/linux/nfs_fs.h Wed Dec 31 19:00:00 1969
+++ linux-0.9pl4/include/linux/nfs_fs.h Wed Dec 1 07:44:15 1993
@@ -0,0 +1,124 @@
+#ifndef _LINUX_NFS_FS_H
+#define _LINUX_NFS_FS_H
+
+/*
+ * linux/include/linux/nfs_fs.h
+ *
+ * Copyright (C) 1992 Rick Sladkey
+ *
+ * OS-specific nfs filesystem definitions and declarations
+ */
+
+#include <linux/nfs.h>
+
+#include <linux/in.h>
+#include <linux/nfs_mount.h>
+
+/*
+ * The readdir cache size controls how many directory entries are cached.
+ * Its size is limited by the number of nfs_entry structures that can fit
+ * in one 4096-byte page, currently 256.
+ */
+
+#define NFS_READDIR_CACHE_SIZE 64
+
+/*
+ * WARNING! The I/O buffer size cannot be bigger than about 3900 for now.
+ * It needs to fit inside a 4096-byte page and leave room for the RPC and
+ * NFS headers. But it ought to at least be a multiple of 512 and probably
+ * should be a power of 2. I don't think Linux TCP/IP can handle more than
+ * about 1800 yet.
+ */
+
+#define NFS_MAX_FILE_IO_BUFFER_SIZE (7*512)
+#define NFS_DEF_FILE_IO_BUFFER_SIZE 1024
+
+/*
+ * The upper limit on timeouts for the exponential backoff algorithm
+ * in tenths of a second.
+ */
+
+#define NFS_MAX_RPC_TIMEOUT 600
+
+/*
+ * Size of the lookup cache in units of number of entries cached.
+ * It is better not to make this too large although the optimimum
+ * depends on a usage and environment.
+ */
+
+#define NFS_LOOKUP_CACHE_SIZE 64
+
+#define NFS_SUPER_MAGIC 0x6969
+
+#define NFS_SERVER(inode) (&(inode)->i_sb->u.nfs_sb.s_server)
+#define NFS_FH(inode) (&(inode)->u.nfs_i.fhandle)
+
+/* linux/fs/nfs/proc.c */
+
+extern int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr);
+extern int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_sattr *sattr, struct nfs_fattr *fattr);
+extern int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr);
+extern int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
+ char *res);
+extern int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
+ int offset, int count, char *data,
+ struct nfs_fattr *fattr);
+extern int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
+ int offset, int count, char *data,
+ struct nfs_fattr *fattr);
+extern int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name, struct nfs_sattr *sattr,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr);
+extern int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name);
+extern int nfs_proc_rename(struct nfs_server *server,
+ struct nfs_fh *old_dir, const char *old_name,
+ struct nfs_fh *new_dir, const char *new_name);
+extern int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fh *dir, const char *name);
+extern int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name, const char *path, struct nfs_sattr *sattr);
+extern int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name, struct nfs_sattr *sattr,
+ struct nfs_fh *fhandle, struct nfs_fattr *fattr);
+extern int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir,
+ const char *name);
+extern int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
+ int cookie, int count, struct nfs_entry *entry);
+extern int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
+ struct nfs_fsinfo *res);
+
+/* linux/fs/nfs/sock.c */
+
+extern int nfs_rpc_call(struct nfs_server *server, int *start, int *end);
+
+/* linux/fs/nfs/inode.c */
+
+extern struct super_block *nfs_read_super(struct super_block *sb,
+ void *data,int);
+extern struct inode *nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle,
+ struct nfs_fattr *fattr);
+extern void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr);
+
+/* linux/fs/nfs/file.c */
+
+extern struct inode_operations nfs_file_inode_operations;
+
+/* linux/fs/nfs/dir.c */
+
+extern struct inode_operations nfs_dir_inode_operations;
+
+/* linux/fs/nfs/symlink.c */
+
+extern struct inode_operations nfs_symlink_inode_operations;
+
+/* linux/fs/nfs/mmap.c */
+
+extern int nfs_mmap(struct inode * inode, struct file * file,
+ unsigned long addr, size_t len, int prot, unsigned long off);
+
+#endif
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/include/linux/nfs_mount.h linux-0.9pl4/include/linux/nfs_mount.h
--- linux-0.9pl3/include/linux/nfs_mount.h Wed Dec 31 19:00:00 1969
+++ linux-0.9pl4/include/linux/nfs_mount.h Wed Dec 1 07:44:15 1993
@@ -0,0 +1,48 @@
+#ifndef _LINUX_NFS_MOUNT_H
+#define _LINUX_NFS_MOUNT_H
+
+/*
+ * linux/include/linux/nfs_mount.h
+ *
+ * Copyright (C) 1992 Rick Sladkey
+ *
+ * structure passed from user-space to kernel-space during an nfs mount
+ */
+
+/*
+ * WARNING! Do not delete or change the order of these fields. If
+ * a new field is required then add it to the end. The version field
+ * tracks which fields are present. This will ensure some measure of
+ * mount-to-kernel version compatibilty. Some of these aren't used yet
+ * but here they are anyway.
+ */
+
+#define NFS_MOUNT_VERSION 1 /* current version */
+
+struct nfs_mount_data {
+ int version; /* 1 */
+ int fd; /* 1 */
+ struct nfs_fh root; /* 1 */
+ int flags; /* 1 */
+ int rsize; /* 1 */
+ int wsize; /* 1 */
+ int timeo; /* 1 */
+ int retrans; /* 1 */
+ int acregmin; /* 1 */
+ int acregmax; /* 1 */
+ int acdirmin; /* 1 */
+ int acdirmax; /* 1 */
+ struct sockaddr_in addr; /* 1 */
+ char hostname[256]; /* 1 */
+};
+
+/* bits in the flags field */
+
+#define NFS_MOUNT_SOFT 0x0001 /* 1 */
+#define NFS_MOUNT_INTR 0x0002 /* 1 */
+#define NFS_MOUNT_SECURE 0x0004 /* 1 */
+#define NFS_MOUNT_POSIX 0x0008 /* 1 */
+#define NFS_MOUNT_NOCTO 0x0010 /* 1 */
+#define NFS_MOUNT_NOAC 0x0020 /* 1 */
+
+#endif
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/include/linux/wait.h linux-0.9pl4/include/linux/wait.h
--- linux-0.9pl3/include/linux/wait.h Sun Aug 14 10:29:35 1994
+++ linux-0.9pl4/include/linux/wait.h Sat Nov 5 11:41:43 1994
@@ -23,6 +23,7 @@
};
#define MUTEX ((struct semaphore) { 1, NULL })
+#define MUTEX_LOCKED ((struct semaphore) { 0, NULL })
struct select_table_entry {
struct wait_queue wait;
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/init/main.c linux-0.9pl4/init/main.c
--- linux-0.9pl3/init/main.c Sun Aug 14 10:29:10 1994
+++ linux-0.9pl4/init/main.c Thu Nov 24 22:17:11 1994
@@ -164,6 +164,7 @@
static char command_line[COMMAND_LINE_SIZE] = { 0, };
struct bootinfo boot_info = {0,};
+int bisize = sizeof boot_info;
char *get_options(char *str, int *ints)
{
@@ -329,7 +330,7 @@
for (n = 0 ; devnames[n] ; n++) {
int len = strlen(devnames[n]);
if (!strncmp(line,devnames[n],len)) {
- ROOT_DEV = devnums[n]+simple_strtoul(line+len,NULL,16);
+ ROOT_DEV = devnums[n]+simple_strtoul(line+len,NULL,10);
break;
}
}
@@ -561,7 +562,7 @@
#ifdef __i386__
sprintf(term, "TERM=con%dx%d", ORIG_VIDEO_COLS, ORIG_VIDEO_LINES);
#else
- sprintf(term, "TERM=vt100");
+ sprintf(term, "TERM=console");
#endif
(void) open("/dev/tty1",O_RDWR,0);
(void) dup(0);
@@ -576,6 +577,7 @@
close(0);
if (open("/etc/rc",O_RDONLY,0))
_exit(1);
+
execve("/bin/sh",argv_rc,envp_rc);
_exit(2);
}
@@ -595,6 +597,7 @@
(void) dup(0);
_exit(execve("/bin/sh",argv,envp));
}
+
while (1)
if (pid == wait(&i))
break;
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/kernel/printk.c linux-0.9pl4/kernel/printk.c
--- linux-0.9pl3/kernel/printk.c Sun Aug 14 10:30:34 1994
+++ linux-0.9pl4/kernel/printk.c Mon Nov 21 18:09:04 1994
@@ -179,7 +179,10 @@
if (log_size < LOG_BUF_LEN)
log_size++;
else
+ {
log_start++;
+ log_start &= LOG_BUF_LEN - 1;
+ }
logged_chars++;
if (*p == '\n')
break;
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/m68k/head.S linux-0.9pl4/m68k/head.S
--- linux-0.9pl3/m68k/head.S Tue Sep 27 22:24:23 1994
+++ linux-0.9pl4/m68k/head.S Mon Nov 21 18:30:44 1994
@@ -9,6 +9,9 @@
** Atari support by Andreas Schwab, using ideas of Robert de Vries
** and Bjoern Brauel
**
+** 94/11/14 Andreas Schwab: put kernel at KSTART_ADDR + PAGESIZE
+** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari
+**
** This file is subject to the terms and conditions of the GNU General Public
** License. See the file README.legal in the main directory of this archive
** for more details.
@@ -37,7 +40,7 @@
*/
.text
-.globl _start, _krt, _kpt, _availmem
+.globl _krt, _kpt, _availmem
PAGESIZE = 4096
KSTART_ADDR = 0xC0000000
@@ -103,6 +106,24 @@
movel d0,sp
/*
+ * Copy bootinfo from position after BSS to final resting place
+ */
+ lea pc@(_end),a0
+ lea pc@(_boot_info),a1
+ movel pc@(_bisize),d0
+ subql #1,d0
+1: moveb a0@+,a1@+
+ dbra d0,1b
+
+/*
+ * Record the CPU and machine type.
+ */
+ lea pc@(_boot_info),a0
+ lea pc@(_end),a0
+ movel a0@(BI_CPU),d6
+ movel a0@(BI_MACH),d4
+
+/*
* Initialize serial port
*/
bsr Lserial_init
@@ -115,13 +136,6 @@
bsr Lserial_putc
/*
- * Record the CPU and machine type.
- */
- lea pc@(_boot_info),a0
- movel a0@(BI_CPU),d6
- movel a0@(BI_MACH),d4
-
-/*
* Get address at end of kernel code/data/bss and
* mask off at a page boundary.
*/
@@ -197,7 +211,7 @@
bnes 1f
/* 680[23]0 */
- lea pc@(_start:w),a1 /* base address */
+ lea pc@(_start-PAGESIZE:w),a1 /* base address */
addql #PAGEDESC,a1 /* descriptor type */
movel #0x40000,d2 /* increment */
bras 2f
@@ -232,7 +246,7 @@
bsr Lserial_putc
movel pc@(_kpt),a0
- lea pc@(_start),a1
+ lea pc@(_start-PAGESIZE:w),a1
addw #(GLOBAL+CM_CACHE_CB+PAGEDESC),a1
movew #((PAGESIZE/4)-1),d1
movel #PAGESIZE,d2
@@ -248,7 +262,7 @@
* all pointer tables utilitized thus far) and the
* kernel page table.
*/
- lea pc@(_start),a0
+ lea pc@(_start-PAGESIZE:w),a0
movel a5,d0 /* address of root table */
subl a0,d0 /* determine offset of root table page */
moveq #PAGE_INDEX_SHIFT,d1 /* determine offset into kernel page table */
@@ -356,7 +370,7 @@
* noncachable/serialized.
*/
movel a3,d0 /* ami page table start address */
- lea pc@(_start:w),a0
+ lea pc@(_start-PAGESIZE:w),a0
subl a0,d0 /* determine offset of root table page */
moveq #12,d1 /* determine offset into kernel page table */
lsrl d1,d0
@@ -381,10 +395,10 @@
/* On the Atari, duplicate the i/o region at 0xfffxxxxx and
mark it non-cachable, set up an identity translation of the first
- 16M. We need two additional page tables for this */
+ 16M. We need two additional pointer tables for this */
lea a5@(1024),a0
- addl #2,a0
+ addl #TABLEDESC,a0
movel a0,a5@(508) /* 0xFE000000 - 0xFFFFFFFF */
lea a5@(1024),a0
@@ -393,8 +407,8 @@
1: movel d0,a0@+
dbra d2,1b
-/* Identity mapping of the last 16M of virtual address space
- to the first 16M for efficient addressing of hardware registers */
+/* Mapping of the last 16M of virtual address space to the first 16M
+ for efficient addressing of hardware registers */
movel #0x40000,d1
movel #63,d2
movel #PAGEDESC,d0
@@ -409,6 +423,7 @@
lea a5@(1536+TABLEDESC),a0
movel a0,a5@
+#if 0 /* this is not needed any more */
/* Identity mapping of the first 16M of virtual address space */
lea a5@(1536),a0
movel #PAGEDESC,d0
@@ -427,6 +442,7 @@
movel #63,d2
1: movel d0,a0@+
dbra d2,1b
+#endif
bra Lmapphys
@@ -462,7 +478,7 @@
*/
2:
- lea pc@(_start:w),a0 /* get address of start of memory */
+ lea pc@(_start-PAGESIZE:w),a0 /* get address of start of memory */
cmpl a0,d0 /* compare limit to start */
bhi Lnophys
@@ -478,7 +494,7 @@
* in the root table. a0 contains the start address of the
* kernel.
*/
- lea pc@(_start:w),a0
+ lea pc@(_start-PAGESIZE:w),a0
movel a0,d2
moveq #25,d3 /* find appropriate index in root table */
lsrl d3,d2
@@ -493,7 +509,7 @@
* registers to identity map the 16M chunk that contains
* the physical memory.
*/
- lea pc@(_start:w),a0
+ lea pc@(_start-PAGESIZE:w),a0
movel a0,d2
andl #0xff000000,d2 /* logical address base */
orw #0xc040,d2 /* add in magic bits */
@@ -504,31 +520,20 @@
cmpl #MACH_ATARI,d4
bnes Lnophys2
- /* if kernel runs in tt-ram, identity map its address space,
- to be removed later */
-
- lea pc@(_start:w),a1
- cmpl #0x1000000,a1
- bcs Lnophys2
+ /* Temporarily set up an identity mapping of the 32MB chunk
+ where the kernel is executing */
/* cleanup is needed; note it */
moveq #1,d5
- /* this assumes that the kernel is in the first 12M of tt-ram,
- otherwise we would have to set up an additional pointer table */
- movel a1,d2
- moveq #18,d3 /* find appropriate index in pointer table */
+ lea pc@(_start-PAGESIZE:w),a0
+ movel a0,d2
+ moveq #25,d3 /* find appropriate index in root table */
lsrl d3,d2
movel d2,d0
lsll d3,d0 /* convert address into descriptor */
addql #PAGEDESC,d0
- movel #1<<18,d1
- lea a5@(1536),a0
- lea a0@(d2:l:4),a0
- moveq #15,d2
-1: movel d0,a0@+ /* store mapping */
- addl d1,d0
- dbra d2,1b
+ movel d0,a5@(d2:l:4) /* store mapping */
Lnophys2:
@@ -542,7 +547,7 @@
moveq #'K',d7
bsr Lserial_putc
- lea pc@(Lmmu),a0
+ lea pc@(mmu),a0
movel #0x80000002,a0@ /* no limit, 4byte descriptors */
movel a5,a0@(4)
pmove a0@,srp
@@ -577,7 +582,7 @@
bsr Lserial_putc
movel #KSTART_ADDR,d0
- lea pc@(_start:w),a0
+ lea pc@(_start-PAGESIZE:w),a0
movel _kpt,d1
subl a0,d1
@@ -609,7 +614,7 @@
lea pc@(tmp_fault_handler),a0
move.l a0,8 /* Access fault vector */
- lea pc@(_start:w),a0
+ lea pc@(_start-PAGESIZE:w),a0
jmp Lvirt:l
Lvirt:
@@ -628,30 +633,17 @@
/* clean up physical identity mapping for 68020/68030 */
cmpl #MACH_AMIGA,d4
- bne Lnoamiclean
+ beqs Lclean030
+ cmpl #MACH_ATARI,d4
+ bnes Lnoclean
+Lclean030:
movel a0,d2 /* a0 contains physical start address */
moveq #25,d3 /* find appropriate index in root table */
lsrl d3,d2
moveq #0,d0
movel d0,a5@(d2:l:4) /* clear descriptor */
-Lnoamiclean:
-
- cmpl #MACH_ATARI,d4
- bne Lnoclean
-
- movel a0,d2 /* a0 contains physical start address */
- moveq #18,d3 /* find appropriate index in pointer table */
- lsrl d3,d2
- moveq #0,d0
- lea a5@(1536),a1
- lea a1@(d2:l:4),a1
- moveq #15,d5
-1: movel d0,a1@+ /* clear descriptor */
- dbra d5,1b
-
- pflusha /* flush address translation cache */
bras Lnoclean
Loff040:
@@ -956,7 +948,7 @@
moveq #'=',d7
bsr Lserial_putc
- lea pc@(Lmmu),a1
+ lea pc@(mmu),a1
pmove psr,a1@
clrl d7
movew a1@,d7
@@ -971,7 +963,7 @@
rts
.data
-Lmmu: .quad 0
+mmu: .quad 0
_krt: .long 0
_kpt: .long 0
_availmem:
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/m68k/ints.c linux-0.9pl4/m68k/ints.c
--- linux-0.9pl3/m68k/ints.c Sun Aug 14 10:29:37 1994
+++ linux-0.9pl4/m68k/ints.c Sat Nov 12 09:51:47 1994
@@ -167,7 +167,7 @@
}
}
-#define DEBUG_LOST_INT_DECR
+#undef DEBUG_LOST_INT_DECR
asmlinkage void process_int(int level, struct intframe *fp)
{
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/m68k/signal.c linux-0.9pl4/m68k/signal.c
--- linux-0.9pl3/m68k/signal.c Sun Aug 14 10:29:37 1994
+++ linux-0.9pl4/m68k/signal.c Thu Oct 20 22:51:01 1994
@@ -308,6 +308,40 @@
current->state = TASK_STOPPED;
notify_parent(current);
schedule();
+ /* ++andreas: discard the extra stuff from the
+ stack frame and always return with a four-word
+ frame. */
+ switch (regs->format)
+ {
+ case 0:
+ break;
+ case 2:
+ regs->stkadj = sizeof (regs->un.fmt2);
+ break;
+ case 3:
+ regs->stkadj = sizeof (regs->un.fmt3);
+ break;
+ case 4:
+ regs->stkadj = sizeof (regs->un.fmt4);
+ break;
+ case 7:
+ regs->stkadj = sizeof (regs->un.fmt7);
+ break;
+ case 9:
+ regs->stkadj = sizeof (regs->un.fmt9);
+ break;
+ case 10:
+ regs->stkadj = sizeof (regs->un.fmta);
+ break;
+ case 11:
+ regs->stkadj = sizeof (regs->un.fmtb);
+ break;
+ default:
+ printk ("do_signal: Unknown frame format %#x\n",
+ regs->format);
+ do_exit (SIGSEGV);
+ }
+ regs->format = 0;
if (!(signr = current->exit_code))
continue;
current->exit_code = 0;
@@ -374,7 +408,23 @@
regs->pc -= 2;
}
if (!handler_signal) /* no handler will be called - return 0 */
+ {
+ /* If we are about to discard some frame stuff we must
+ copy over the remaining frame. */
+ if (regs->stkadj)
+ {
+ struct frame *tregs =
+ (struct frame *) ((ulong) regs + regs->stkadj);
+
+ /* This must be copied with decreasing addresses to
+ handle overlaps. */
+ tregs->format = regs->format;
+ tregs->vector = regs->vector;
+ tregs->pc = regs->pc;
+ tregs->sr = regs->sr;
+ }
return 0;
+ }
pc = regs->pc;
frame = (unsigned long *)regs->usp;
signr = 1;
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/m68k/sys_call.S linux-0.9pl4/m68k/sys_call.S
--- linux-0.9pl3/m68k/sys_call.S Sun Aug 28 17:16:21 1994
+++ linux-0.9pl4/m68k/sys_call.S Sat Nov 12 09:52:25 1994
@@ -90,6 +90,17 @@
LTS_FLAGS = 20
LTS_ERRNO = 24
+#include <linux/autoconf.h>
+
+/* the following macro is used when enabling interrupts */
+#if defined(CONFIG_ATARI) && !defined(CONFIG_AMIGA) && !defined(CONFIG_MAC)
+ /* block out HSYNC on the atari */
+#define ALLOWINT 0xfbff
+#else
+ /* portable version */
+#define ALLOWINT 0xf8ff
+#endif /* machine compilation types */
+
.globl _system_call, _buserr, _trap
.globl _ret_from_exception, _inthandler
@@ -280,12 +291,12 @@
bne 1f
movel _bh_mask,d0
- andl d0,_bh_active
+ andl _bh_active,d0
beq 1f
movew sr,sp@-
addql #1,_intr_count
- andiw #0xf8ff,sr | allow interrupts
+ andiw #(ALLOWINT),sr | allow interrupts
jbsr _do_bottom_half
movew sp@+,sr
subql #1,_intr_count
@@ -311,7 +322,7 @@
Lnotkernel:
addql #8,sp | throw away throwaway stack frame
oriw #0x1000,sr | set master bit in SR (sp is now msp)
- andiw #0xf8ff,sr | allow interrupts
+ andiw #(ALLOWINT),sr | allow interrupts
clrw sp@- | stack adjustment
subql #8,sp | make room for usp and orig_d0
movel d0,sp@- | save registers as for syscall
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/m68k/traps.c linux-0.9pl4/m68k/traps.c
--- linux-0.9pl3/m68k/traps.c Sun Aug 28 17:16:21 1994
+++ linux-0.9pl4/m68k/traps.c Mon Nov 21 18:09:06 1994
@@ -284,13 +284,13 @@
printk ("SSW=%#06x ", ssw);
if (ssw & (FC | FB))
- printk ("Instruction fault at %#010x\n",
+ printk ("Instruction fault at %#010lx\n",
ssw & FC ?
fp->format == 0xa ? fp->pc + 2 : fp->un.fmtb.baddr - 2
:
fp->format == 0xa ? fp->pc + 4 : fp->un.fmtb.baddr);
if (ssw & DF)
- printk ("Data %s fault at %#010x in %s (pc=%#lx)\n",
+ printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n",
ssw & RW ? "read" : "write",
fp->un.fmtb.daddr,
space_names[ssw & DFC], fp->pc);
@@ -393,7 +393,7 @@
(but only if the page is now valid). Otherwise we'll get
an wierd read access. */
/* XXX can this condition be simplified? */
- if (ssw & DF && ssw & RB && mmusr & MMU_I
+ if (ssw & DF && ssw & RB && (mmusr & MMU_I)
&& (addr & PAGE_MASK) == (fp->un.fmtb.baddr & PAGE_MASK))
{
asm volatile ("ptestr #1,%1@,#7\n\t"
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/mm/memory.c linux-0.9pl4/mm/memory.c
--- linux-0.9pl3/mm/memory.c Sun Aug 14 10:29:39 1994
+++ linux-0.9pl4/mm/memory.c Mon Nov 21 18:32:45 1994
@@ -85,7 +85,7 @@
/*
* oom() prints a message (so that the user knows why the process died),
- * and gives the process an untrappable SIGSEGV.
+ * and gives the process an untrappable SIGKILL.
*/
void oom(struct task_struct * task)
{
@@ -271,7 +271,9 @@
panic("Trying to free up swapper memory space");
}
root = tsk->tss.pagedir_v;
- if (!root || root == task[0]->tss.pagedir_v) {
+ if (!root)
+ return;
+ if (root == task[0]->tss.pagedir_v) {
printk("Trying to free kernel root table: not good\n");
return;
}
@@ -291,6 +293,8 @@
*/
if (root[NUM_L1_ENTRIES-1] > 0) {
root[NUM_L1_ENTRIES-1]--;
+ tsk->tss.pagedir_v = 0;
+ tsk->tss.pagedir_p = 0;
return;
}
@@ -338,11 +342,11 @@
}
static int copy_pointer_table (struct task_struct *tsk,
- unsigned long old_ptr_desc,
+ unsigned long *old_ptr_table,
unsigned long *new_root)
{
int i;
- unsigned long *old_ptr_table, *new_ptr_table, new_ptr_vaddr;
+ unsigned long *new_ptr_table, new_ptr_vaddr;
/* get a new pointer table, can't allocate, no fork */
if (!(new_ptr_table = get_pointer_table ())) {
@@ -352,13 +356,12 @@
new_ptr_vaddr = (unsigned long)new_ptr_table;
/* process each page table in the pointer table */
- old_ptr_table = (unsigned long *)PTOV(old_ptr_desc & TABLE_MASK);
-
for (i = 0 ; i < NUM_L2_ENTRIES ;
i++,old_ptr_table += 16, new_ptr_table += 16) {
int j;
unsigned long old_pg_table, *old_page_tablep;
unsigned long *new_page_tablep;
+ unsigned long old_pg_table_v;
/* read descriptor for page table */
old_pg_table = *old_ptr_table;
@@ -371,7 +374,8 @@
* if the address is too high, or it is not a short
* descriptor, things are screwy.
*/
- if (PTOV(old_pg_table) >= high_memory
+ old_pg_table_v = PTOV (old_pg_table & PAGE_MASK);
+ if (old_pg_table_v >= high_memory
|| !(old_pg_table & PAGE_TABLE)) {
printk("copy_page_tables: bad page table: "
"probable memory corruption\n");
@@ -383,7 +387,7 @@
* if it is a reserved entry (won't be, with the separate kernel
* and user virtual address spaces for the M68K port.
*/
- if (mem_map[MAP_NR(PTOV(old_pg_table))] & MAP_PAGE_RESERVED) {
+ if (mem_map[MAP_NR(old_pg_table_v)] & MAP_PAGE_RESERVED) {
*new_ptr_table = old_pg_table;
continue;
}
@@ -393,9 +397,9 @@
return -ENOMEM;
/* process each page in the page table */
- old_page_tablep = (unsigned long *)PTOV(old_pg_table & PAGE_MASK);
+ old_page_tablep = (unsigned long *) old_pg_table_v;
for (j = 0 ; j < PTRS_PER_PAGE ; j++,old_page_tablep++,new_page_tablep++) {
- unsigned long pg;
+ unsigned long pg, pg_v;
/* read page descriptor from table */
pg = *old_page_tablep;
@@ -417,10 +421,11 @@
if ((pg & (PAGE_RONLY | PAGE_COW)) == PAGE_COW)
pg |= PAGE_RONLY;
*new_page_tablep = pg;
- if (mem_map[MAP_NR(PTOV(pg & PAGE_MASK))] & MAP_PAGE_RESERVED)
+ pg_v = PTOV (pg & PAGE_MASK);
+ if (mem_map[MAP_NR(pg_v)] & MAP_PAGE_RESERVED)
continue;
*old_page_tablep = pg;
- mem_map[MAP_NR(PTOV(pg & PAGE_MASK))]++;
+ mem_map[MAP_NR(pg_v)]++;
}
}
@@ -460,6 +465,7 @@
for (i = 0 ; i < NUM_L1_ENTRIES-1 ; i++, old_root++,new_root++) {
unsigned long old_ptr_desc;
+ unsigned long vaddr;
/* read descriptor for pointer table */
old_ptr_desc = *old_root;
@@ -472,7 +478,8 @@
* if the address is too high, or it is not a short
* descriptor, things are screwy.
*/
- if (PTOV(old_ptr_desc) >= high_memory
+ vaddr = PTOV (old_ptr_desc & TABLE_MASK);
+ if (vaddr >= high_memory
|| !(old_ptr_desc & PAGE_TABLE)) {
printk("copy_page_tables: bad pointer table: "
"probable memory corruption\n");
@@ -480,7 +487,7 @@
continue;
}
- if (copy_pointer_table (tsk, old_ptr_desc, new_root))
+ if (copy_pointer_table (tsk, (unsigned long *)vaddr, new_root))
return -ENOMEM;
}
end:
@@ -517,10 +524,11 @@
if ((page = *page_table) != 0) {
*page_table = 0;
if (page & PAGE_PRESENT) {
- if (!(mem_map[MAP_NR(PTOV(page & PAGE_MASK))] & MAP_PAGE_RESERVED))
+ unsigned long page_v = PTOV(page & PAGE_MASK);
+ if (!(mem_map[MAP_NR(page_v)] & MAP_PAGE_RESERVED))
if (current->rss > 0)
--current->rss;
- free_page(PTOV(page & PAGE_MASK));
+ free_page(page_v);
} else
swap_free(page);
}
@@ -572,10 +580,11 @@
if ((page = *page_table) != 0) {
*page_table = 0;
if (page & PAGE_PRESENT) {
- if (!(mem_map[MAP_NR(PTOV(page & PAGE_MASK))] & MAP_PAGE_RESERVED))
+ unsigned long page_v = PTOV(page & PAGE_MASK);
+ if (!(mem_map[MAP_NR(page_v)] & MAP_PAGE_RESERVED))
if (current->rss > 0)
--current->rss;
- free_page(PTOV(page & PAGE_MASK));
+ free_page(page_v);
} else
swap_free(page);
}
@@ -636,10 +645,11 @@
if ((page = *page_table) != 0) {
*page_table = 0;
if (page & PAGE_PRESENT) {
- if (!(mem_map[MAP_NR(PTOV(page & PAGE_MASK))] & MAP_PAGE_RESERVED))
+ unsigned long page_v = PTOV(page & PAGE_MASK);
+ if (!(mem_map[MAP_NR(page_v)] & MAP_PAGE_RESERVED))
if (current->rss > 0)
--current->rss;
- free_page(PTOV(page & PAGE_MASK));
+ free_page(page_v);
} else
swap_free(page);
}
@@ -652,7 +662,7 @@
*/
if (!mask)
*page_table = 0; /* not present */
- else if (to >= high_memory)
+ else if (to < KSTART_ADDR || to >= high_memory)
*page_table = (VTOP(to) | mask);
else if (!mem_map[MAP_NR(to)])
*page_table = 0; /* not present */
@@ -788,6 +798,7 @@
{
unsigned long *rootp, desc, *ptep, *ptrp, old_page, prot;
unsigned long new_page;
+ unsigned long vaddr;
#ifdef DEBUG
if (user_usp)
@@ -797,27 +808,28 @@
new_page = __get_free_page(GFP_KERNEL);
rootp = &tsk->tss.pagedir_v[L1_INDEX(address)];
desc = *rootp;
- if ((desc & PAGE_TABLE) != PAGE_TABLE
- || PTOV (desc & TABLE_MASK) >= high_memory)
+ vaddr = PTOV (desc & TABLE_MASK);
+ if ((desc & PAGE_TABLE) != PAGE_TABLE || vaddr >= high_memory)
panic ("do_wp_page: invalid root table entry %08lx", desc);
- ptrp = (unsigned long *)PTOV(desc & TABLE_MASK);
+ ptrp = (unsigned long *) vaddr;
ptrp += L2_INDEX(address);
desc = *ptrp;
- if ((desc & PAGE_TABLE) != PAGE_TABLE
- || PTOV (desc & TABLE_MASK) >= high_memory)
+ vaddr = PTOV (desc & PAGE_MASK);
+ if ((desc & PAGE_TABLE) != PAGE_TABLE || vaddr >= high_memory)
goto bad_wp_pagetable;
- ptep = (unsigned long *)PTOV(desc & PAGE_MASK) + L3_INDEX(address);
+ ptep = (unsigned long *) vaddr + L3_INDEX(address);
old_page = *ptep;
if (!(old_page & PAGE_PRESENT))
goto end_wp_page;
- if (PTOV (old_page) >= high_memory)
+ vaddr = PTOV (old_page & PAGE_MASK);
+ if (vaddr >= high_memory)
goto bad_wp_page;
if (!(old_page & PAGE_RONLY))
goto end_wp_page;
/* minor page fault (copy on write) */
tsk->min_flt++;
prot = ((old_page & ~PAGE_MASK) & ~PAGE_RONLY) | PAGE_RW;
- old_page = PTOV(old_page & PAGE_MASK);
+ old_page = vaddr;
/* if page was used only once (no longer shared) enable read write */
if (mem_map[MAP_NR(old_page)] != 1) {
if (new_page) {
@@ -868,6 +880,7 @@
{
unsigned long page, ptrdesc;
unsigned long *rootp, *pg_table;
+ unsigned long vaddr;
#ifdef DEBUG
printk ("do_wp_page (address=%#lx, user_usp=%#lx\n", address,
@@ -899,8 +912,9 @@
*/
panic ("do_wp_page: unexplained null pointer table entry for %lx", address);
}
- if ((page & PAGE_TABLE) && PTOV(page) < high_memory) {
- pg_table = (unsigned long *)PTOV(page & PAGE_MASK);
+ vaddr = PTOV (page & PAGE_MASK);
+ if ((page & PAGE_TABLE) && vaddr < high_memory) {
+ pg_table = (unsigned long *) vaddr;
pg_table += L3_INDEX(address);
page = *pg_table;
if (!(page & PAGE_PRESENT))
@@ -1050,7 +1064,7 @@
if (!inode || inode->i_count < 2 || !area->vm_ops)
return 0;
for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
- if (!*p)
+ if (!*p || !(*p)->tss.pagedir_v)
continue;
if (tsk == *p)
continue;
@@ -1368,6 +1382,11 @@
do_no_page (error_code, address, current, user_esp);
return;
}
+ if ((fp->un.fmtb.ssw & 4) == 0) {
+ /* User memory access */
+ send_sig (SIGSEGV, current, 1);
+ return;
+ }
printk("Unable to handle kernel paging request at address %08lx from %lx\n",address, fp->pc);
die_if_kernel("Oops", fp, error_code);
do_exit(SIGKILL);
@@ -1508,7 +1527,7 @@
printk("Free pages: %6dkB\n",nr_free_pages<<(PAGE_SHIFT-10));
printk("Secondary pages: %6dkB\n",nr_secondary_pages<<(PAGE_SHIFT-10));
printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10));
- i = (high_memory-0xC0000000) >> PAGE_SHIFT;
+ i = (high_memory-KSTART_ADDR) >> PAGE_SHIFT;
while (i-- > 0) {
total++;
if (mem_map[i] & MAP_PAGE_RESERVED)
@@ -1555,6 +1574,69 @@
offset += boot_info.memory[i].size;
}
+ /* not in one of the memory chunks; get the actual
+ * physical address from the MMU.
+ */
+ if (boot_info.cputype & CPU_68040) {
+ unsigned long mmusr;
+ unsigned short fs = get_fs();
+
+ set_fs (SUPER_DATA);
+
+ asm volatile ("movel %1,a0\n\t"
+ ".word 0xf568\n\t" /* ptestr (a0) */
+ ".long 0x4e7a8805\n\t" /* movec mmusr, a0 */
+ "movel a0,%0"
+ : "=g" (mmusr)
+ : "g" (vaddr)
+ : "a0", "d0");
+ set_fs (fs);
+
+ if (mmusr & MMU_R_040)
+ return (mmusr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1));
+
+ panic ("VTOP040: bad virtual address %08lx (%lx)", vaddr, mmusr);
+ } else {
+ volatile unsigned short temp;
+ unsigned short mmusr;
+ unsigned long *descaddr;
+
+ asm volatile ("ptestr #5,%2@,#7,%0\n\t"
+ "pmove psr,%1@"
+ : "=a&" (descaddr)
+ : "a" (&temp), "a" (vaddr));
+ mmusr = temp;
+
+ printk ("mmusr is %#x for kernel vaddr %#lx\n",
+ mmusr, vaddr);
+
+ if (mmusr & (MMU_I|MMU_B|MMU_L))
+ panic ("VTOP030: bad virtual address %08lx (%x)", vaddr, mmusr);
+
+ descaddr = (unsigned long *)PTOV(descaddr);
+
+ printk ("descriptor address is %p, contents %#lx\n",
+ descaddr, *descaddr);
+
+ switch (mmusr & MMU_NUM) {
+ case 1:
+ printk ("physaddr for %lx is %lx\n", vaddr,
+ (*descaddr & 0xfe000000) | (vaddr & 0x01ffffff));
+ return (*descaddr & 0xfe000000) | (vaddr & 0x01ffffff);
+ case 2:
+ printk ("physaddr for %lx is %lx\n", vaddr,
+ (*descaddr & 0xfffc0000) | (vaddr & 0x0003ffff));
+ return (*descaddr & PAGE_MASK) | (vaddr & 0x0003ffff);
+ case 3:
+ printk ("physaddr for %lx is %lx\n", vaddr,
+ (*descaddr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1)));
+ return (*descaddr & PAGE_MASK) | (vaddr & (PAGE_SIZE-1));
+ default:
+ panic ("VTOP: bad levels (%d) for virtual address %08lx",
+ mmusr & MMU_NUM, vaddr);
+ }
+ }
+
panic ("VTOP: bad virtual address %08lx", vaddr);
}
@@ -1577,8 +1659,21 @@
offset += boot_info.memory[i].size;
}
- panic ("PTOV: bad physical address %08lx (called from %p)\n",
- paddr, __builtin_return_address(0));
+ /*
+ * assume that the kernel virtual address is the same as the
+ * physical address.
+ *
+ * This should be reasonable in most situations:
+ * 1) They shouldn't be dereferencing the virtual address
+ * unless they are sure that it is valid from kernel space.
+ * 2) The only usage I see so far is converting a page table
+ * reference to some non-FASTMEM address space when freeing
+ * mmaped "/dev/mem" pages. These addresses are just passed
+ * to "free_page", which ignores addresses that aren't in
+ * the memory list anyway.
+ *
+ */
+ return paddr;
}
static unsigned long *kernel_pointer_table (void)
@@ -1968,7 +2063,7 @@
virtual_start = availmem;
/* virtual address of end of available memory */
- virtual_end = (unsigned long)start + mem_avail;
+ virtual_end = KSTART_ADDR + mem_avail;
#ifdef DEBUG
printk ("virtual_start is %#lx\nvirtual_end is %#lx\n",
@@ -2060,6 +2155,37 @@
start_mem += PAGE_SIZE;
}
+#ifdef CONFIG_ATARI
+
+ if (boot_info.machtype == MACH_ATARI) {
+
+ /* If the page with physical address 0 isn't the first kernel
+ * code page, it has to be reserved because the first 2 KB of
+ * ST-Ram can only be accessed from supervisor mode by
+ * hardware.
+ */
+
+ unsigned long virt0 = PTOV( 0 ), adr;
+ extern unsigned long rsvd_stram_beg, rsvd_stram_end;
+
+ if (virt0 != KSTART_ADDR) {
+
+ mem_map[MAP_NR(virt0)] = MAP_PAGE_RESERVED;
+
+ /* Also, reserve all pages that have been marked by
+ * stram_alloc() (e.g. for the screen memory). (This may
+ * treat the first ST-Ram page a second time, but that
+ * doesn't hurt...) */
+
+ rsvd_stram_end += PAGE_SIZE - 1;
+ rsvd_stram_end &= PAGE_MASK;
+ rsvd_stram_beg &= PAGE_MASK;
+ for( adr = rsvd_stram_beg; adr < rsvd_stram_end; adr += PAGE_SIZE )
+ mem_map[MAP_NR(adr)] = MAP_PAGE_RESERVED;
+ }
+ }
+
+#endif
#ifdef DEBUG
printk ("task[0] root table is %p\n", task[0]->tss.pagedir_v);
#endif
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/mm/mmap.c linux-0.9pl4/mm/mmap.c
--- linux-0.9pl3/mm/mmap.c Sun Aug 14 10:29:39 1994
+++ linux-0.9pl4/mm/mmap.c Thu Nov 24 21:10:20 1994
@@ -48,6 +48,9 @@
{
int mask, error;
+ if ((len = PAGE_ALIGN(len)) == 0)
+ return addr;
+
if (addr > TASK_SIZE || len > TASK_SIZE || addr > TASK_SIZE-len)
return -EINVAL;
@@ -110,13 +113,15 @@
if (file && (!file->f_op || !file->f_op->mmap))
return -ENODEV;
mask = 0;
- if (prot & (PROT_READ | PROT_EXEC))
+ if (!(prot & PROT_WRITE))
mask |= PAGE_READONLY;
- if (prot & PROT_WRITE)
+ if (prot & PROT_WRITE) {
+ mask &= ~PAGE_READONLY;
if ((flags & MAP_TYPE) == MAP_PRIVATE)
mask |= PAGE_COPY;
else
mask |= PAGE_SHARED;
+ }
if (!mask)
return -EINVAL;
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/mm/swap.c linux-0.9pl4/mm/swap.c
--- linux-0.9pl3/mm/swap.c Mon Sep 19 22:00:57 1994
+++ linux-0.9pl4/mm/swap.c Mon Oct 10 16:48:32 1994
@@ -321,7 +321,6 @@
int counter = NR_TASKS * 2 >> priority;
struct task_struct *p;
- counter = NR_TASKS * 2 >> priority;
for(; counter >= 0; counter--, swap_task++) {
/*
* Check that swap_task is suitable for swapping. If not, look for
@@ -366,30 +365,36 @@
/* On the m68k, the last entry in the root table is the use
count, it must not be touched */
for(table = p->swap_table; table < 1024 - 8; table++) {
- unsigned long desc, *ptr;
+ unsigned long desc, desc_p, *ptr;
+ unsigned long pg_table_p;
- desc = L1_SWAP_INDEX(p->tss.pagedir_v,table);
- if(!desc || PTOV(desc & TABLE_MASK) >= high_memory)
+ desc_p = L1_SWAP_INDEX(p->tss.pagedir_v,table);
+ if (!desc_p)
continue;
- if(!(PAGE_TABLE & desc)) {
+ desc = PTOV (desc_p & TABLE_MASK);
+ if (desc >= high_memory)
+ continue;
+ if (!(PAGE_TABLE & desc_p)) {
printk("swap_out: bad page-table at pg_dir[%d]: %08lx\n",
- table, desc);
+ table, desc_p);
L1_SWAP_INDEX(p->tss.pagedir_v,table) = 0;
continue;
}
- ptr = (unsigned long *)PTOV(desc & TABLE_MASK);
- pg_table = L2_SWAP_INDEX(ptr,table);
- if (!pg_table || PTOV(pg_table & PAGE_MASK) >= high_memory)
+ ptr = (unsigned long *) desc;
+ pg_table_p = L2_SWAP_INDEX(ptr,table);
+ if (!pg_table_p)
continue;
- if(mem_map[MAP_NR(PTOV(pg_table & PAGE_MASK))] & MAP_PAGE_RESERVED)
+ pg_table = PTOV (pg_table_p & PAGE_MASK);
+ if (pg_table >= high_memory)
continue;
- if(!(PAGE_TABLE & pg_table)) {
+ if (mem_map[MAP_NR(pg_table)] & MAP_PAGE_RESERVED)
+ continue;
+ if (!(PAGE_TABLE & pg_table_p)) {
printk("swap_out: bad page-table at pg_dir[%d]: %08lx\n",
- table, pg_table);
+ table, pg_table_p);
L2_SWAP_INDEX(ptr,table) = 0;
continue;
}
- pg_table = PTOV(pg_table & PAGE_MASK);
/*
* Go through this page table.
@@ -661,8 +666,8 @@
if (intr_count && priority != GFP_ATOMIC) {
static int count = 0;
if (++count < 5) {
- printk("gfp called nonatomically from interrupt %08lx\n",
- ((unsigned long *)&priority)[-1]);
+ printk("gfp called nonatomically from interrupt %p\n",
+ __builtin_return_address (0));
priority = GFP_ATOMIC;
}
}
@@ -703,19 +708,21 @@
continue;
for (pgt = 0 ; pgt < PTRS_PER_PAGE ; pgt++) {
desc = L1_SWAP_INDEX(p->tss.pagedir_v,pgt);
- if (!desc)
+ if (!desc || !(desc & PAGE_TABLE))
continue;
- if (!(desc & PAGE_TABLE) || PTOV(desc & TABLE_MASK) >= high_memory)
+ desc = PTOV (desc & TABLE_MASK);
+ if (desc >= high_memory)
continue;
- ptr = (unsigned long *)PTOV(desc & TABLE_MASK);
+ ptr = (unsigned long *) desc;
page = L2_SWAP_INDEX(ptr,pgt);
- if (!page)
+ if (!page || !(page & PAGE_TABLE))
continue;
- if (!(page & PAGE_PRESENT) || (PTOV(page & PAGE_MASK) >= high_memory))
+ page = PTOV (page & PAGE_MASK);
+ if (page >= high_memory)
continue;
- if (mem_map[MAP_NR(PTOV(page & PAGE_MASK))] & MAP_PAGE_RESERVED)
+ if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED)
continue;
- ppage = (unsigned long *) PTOV(page & PAGE_MASK);
+ ppage = (unsigned long *) page;
for (pg = 0 ; pg < PTRS_PER_PAGE ; pg++,ppage++) {
page = *ppage;
if (!page)
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/mm/vmalloc.c linux-0.9pl4/mm/vmalloc.c
--- linux-0.9pl3/mm/vmalloc.c Sun Aug 14 10:29:39 1994
+++ linux-0.9pl4/mm/vmalloc.c Sat Nov 5 13:08:33 1994
@@ -137,8 +137,8 @@
if (!(PAGE_TABLE & (ptr = krt[dindex >> 3])))
return 0;
ptrp = (unsigned long *)PTOV(ptr & TABLE_MASK);
- ptrp += (16*sizeof(long))*(dindex & (NUM_L2_ENTRIES-1));
- if (!(PAGE_TABLE & (page = ptrp[16*(dindex & (NUM_L2_ENTRIES-1))])))
+ ptrp += 16*(dindex & (NUM_L2_ENTRIES-1));
+ if (!(PAGE_TABLE & (page = *ptrp)))
return 0;
page = PTOV(page & PAGE_MASK);
pte = index + (unsigned long *) page;
@@ -154,7 +154,7 @@
if (*pte)
return 0;
mem_map[MAP_NR(page)] &= ~MAP_PAGE_RESERVED;
- free_page_table(&ptrp[16*(dindex & (NUM_L2_ENTRIES-1))]);
+ free_page_table(ptrp);
return 0;
}
@@ -175,9 +175,10 @@
krt[dindex >> 3] = VTOP(ptrp) | PAGE_TABLE;
} else
ptrp = (unsigned long *)PTOV(ptr & TABLE_MASK);
- page = ptrp[16*(dindex & (NUM_L2_ENTRIES-1))];
+ ptrp += 16*(dindex & (NUM_L2_ENTRIES-1));
+ page = *ptrp;
if (!page) {
- page = (unsigned long)get_page_table (&ptrp[16*(dindex & (NUM_L2_ENTRIES-1))]);
+ page = (unsigned long)get_page_table (ptrp);
if (!page)
return -ENOMEM;
else
@@ -240,7 +241,8 @@
for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
if (tmp->addr == addr) {
*p = tmp->next;
- do_area(tmp->addr, tmp->size, free_area_pages);
+ do_area(tmp->addr, tmp->size - PAGE_SIZE,
+ free_area_pages);
kfree(tmp);
return;
}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/net/inet/dev.c linux-0.9pl4/net/inet/dev.c
--- linux-0.9pl3/net/inet/dev.c Tue Sep 27 20:50:20 1994
+++ linux-0.9pl4/net/inet/dev.c Mon Oct 10 16:48:34 1994
@@ -134,6 +134,7 @@
struct packet_type *ptype_base = &ip_packet_type;
static struct sk_buff *volatile backlog = NULL;
+static int backlog_size = 0;
static unsigned long ip_bcast = 0;
@@ -482,13 +483,24 @@
void
netif_rx(struct sk_buff *skb)
{
+ static int dropping = 0;
/* Set any necessary flags. */
skb->sk = NULL;
skb->free = 1;
+ /* check that we aren't oevrdoing things.. */
+ if (!backlog_size)
+ dropping = 0;
+ else if (backlog_size > 100)
+ dropping = 1;
+ if (dropping) {
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
/* and add it to the "backlog" queue. */
IS_SKB(skb);
skb_queue_tail(&backlog,skb);
+ backlog_size++;
/* If any packet arrived, mark it for processing. */
if (backlog != NULL) mark_bh(INET_BH);
@@ -607,6 +619,7 @@
/* Any data left to process? */
while((skb=skb_dequeue(&backlog))!=NULL)
{
+ backlog_size--;
nitcount=dev_nit;
flag=0;
sti();
@@ -637,9 +650,6 @@
* to anyone who wants it.
*/
for (ptype = ptype_base; ptype != NULL; ptype = ptype->next) {
- DPRINTF((DBG_DEV,
- "INET: type is %x, comparing to %x\n", type,
- ptype->type));
if (ptype->type == type || ptype->type == NET16(ETH_P_ALL)) {
struct sk_buff *skb2;
@@ -735,6 +745,9 @@
memcpy_fromfs(&ifc, arg, sizeof(struct ifconf));
len = ifc.ifc_len;
pos = ifc.ifc_buf;
+ err=verify_area(VERIFY_WRITE, pos, len);
+ if(err)
+ return err;
/* Loop over the interfaces, and write an info block for each. */
for (dev = dev_base; dev != NULL; dev = dev->next) {
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/net/inet/eth.c linux-0.9pl4/net/inet/eth.c
--- linux-0.9pl3/net/inet/eth.c Tue Sep 27 20:51:24 1994
+++ linux-0.9pl4/net/inet/eth.c Mon Oct 10 16:48:34 1994
@@ -106,7 +106,6 @@
/* Fill in the basic Ethernet MAC header. */
eth = (struct ethhdr *) buff;
eth->h_proto = htons(type);
- DPRINTF((DBG_DEV, "ETH: eth->h_proto = %x)\n", eth->h_proto));
/* We don't ARP for the LOOPBACK device... */
if (dev->flags & IFF_LOOPBACK) {
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/net/inet/icmp.c linux-0.9pl4/net/inet/icmp.c
--- linux-0.9pl3/net/inet/icmp.c Tue Mar 1 11:51:41 1994
+++ linux-0.9pl4/net/inet/icmp.c Mon Oct 10 16:48:35 1994
@@ -285,6 +285,65 @@
}
+/* Handle ICMP Timestamp requests. */
+static void
+icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
+ unsigned long saddr, unsigned long daddr, int len,
+ struct options *opt)
+{
+ struct icmphdr *icmphr;
+ struct sk_buff *skb2;
+ int size, offset;
+ unsigned long *timeptr, midtime;
+ extern struct timeval xtime; /* kernel/time.c */
+
+ size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
+ if (! (skb2 = alloc_skb(size, GFP_ATOMIC))) {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+ skb2->sk = NULL;
+ skb2->mem_addr = skb2;
+ skb2->mem_len = size;
+ skb2->free = 1;
+
+ /* Build Layer 2-3 headers for message back to source */
+ offset = ip_build_header(skb2, daddr, saddr, &dev, IPPROTO_ICMP, opt, len,
+ skb->ip_hdr->tos, 255);
+ if (offset < 0) {
+ printk("ICMP: Could not build IP Header for ICMP TIMESTAMP Response\n");
+ kfree_skb(skb2, FREE_WRITE);
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return;
+ }
+
+ /* Re-adjust length according to actual IP header size. */
+ skb2->len = offset + len;
+
+ /* Build ICMP_TIMESTAMP Response message. */
+ icmphr = (struct icmphdr *) ((char *) (skb2 + 1) + offset);
+ memcpy((char *) icmphr, (char *) icmph, len);
+ icmphr->type = ICMP_TIMESTAMPREPLY;
+ icmphr->code = icmphr->checksum = 0;
+
+ /* fill in the current time as ms since midnight UT: */
+ midtime = (xtime.tv_sec % 86400) * 1000 + xtime.tv_usec / 1000;
+ timeptr = (unsigned long *) (icmphr + 1);
+ /* the originate timestamp (timeptr [0]) is still in the copy: */
+ timeptr [1] = timeptr [2] = htonl(midtime);
+
+ icmphr->checksum = ip_compute_csum((unsigned char *) icmphr, len);
+
+ /* Ship it out - free it when done */
+ ip_queue_xmit((struct sock *) NULL, dev, skb2, 1);
+
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+}
+
+
/* Handle the ICMP INFORMATION REQUEST. */
static void
icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
@@ -397,6 +456,13 @@
icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt);
return 0;
case ICMP_ECHOREPLY:
+ skb1->sk = NULL;
+ kfree_skb(skb1, FREE_READ);
+ return(0);
+ case ICMP_TIMESTAMP:
+ icmp_timestamp(icmph, skb1, dev, saddr, daddr, len, opt);
+ return 0;
+ case ICMP_TIMESTAMPREPLY:
skb1->sk = NULL;
kfree_skb(skb1, FREE_READ);
return(0);
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/net/inet/ip.c linux-0.9pl4/net/inet/ip.c
--- linux-0.9pl3/net/inet/ip.c Mon Sep 26 19:24:28 1994
+++ linux-0.9pl4/net/inet/ip.c Mon Oct 10 16:48:38 1994
@@ -10,6 +10,7 @@
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.org>
+ * Alan Cox, <gw4pts@gw4pts.ampr.org>
*
* Fixes:
* Alan Cox : Commented a couple of minor bits of surplus code
@@ -40,6 +41,9 @@
* Alan Cox : Silly ip bug when an overlength
* fragment turns up. Now frees the
* queue.
+ * Linus Torvalds/ : Memory leakage on fragmentation
+ * Alan Cox : handling.
+ * Gerhard Koerting: Forwarding uses IP priority hints
*
* To Fix:
* IP option processing is mostly not needed. ip_forward needs to know about routing rules
@@ -238,7 +242,7 @@
return(-ENETUNREACH);
*dev = rt->rt_dev;
- if (saddr == 0x0100007FL && daddr != 0x0100007FL)
+ if (saddr == htonl (0x7F000001L) && daddr != htonl (0x7F000001L))
saddr = rt->rt_dev->pa_addr;
raddr = rt->rt_gateway;
@@ -891,8 +895,7 @@
offset = ntohs(iph->frag_off);
flags = offset & ~IP_OFFSET;
offset &= IP_OFFSET;
- if (((flags & IP_MF) == 0) && (offset == 0))
- {
+ if (((flags & IP_MF) == 0) && (offset == 0)) {
if (qp != NULL)
ip_free(qp); /* Huh? How could this exist?? */
return(skb);
@@ -904,18 +907,18 @@
* as we still are receiving fragments. Otherwise, create a fresh
* queue entry.
*/
- if (qp != NULL)
- {
+ if (qp != NULL) {
del_timer(&qp->timer);
qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */
qp->timer.data = (unsigned long) qp; /* pointer to queue */
qp->timer.function = ip_expire; /* expire function */
add_timer(&qp->timer);
+ } else {
+ if ((qp = ip_create(skb, iph, dev)) == NULL) {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return NULL;
}
- else
- {
- if ((qp = ip_create(skb, iph, dev)) == NULL)
- return(NULL);
}
/* Determine the position of this fragment. */
@@ -984,6 +987,7 @@
if (tfp->next != NULL)
next->next->prev = next->prev;
+ kfree_skb(next->skb, FREE_READ);
kfree_s(next, sizeof(struct ipfrag));
}
DPRINTF((DBG_IP, "IP: defrag: fixed high overlap %d bytes\n", i));
@@ -992,6 +996,11 @@
/* Insert this fragment in the chain of fragments. */
tfp = NULL;
tfp = ip_frag_create(offset, end, skb, ptr);
+ if (!tfp) {
+ skb->sk = NULL;
+ kfree_skb(skb, FREE_READ);
+ return NULL;
+ }
tfp->prev = prev;
tfp->next = next;
if (prev != NULL)
@@ -1052,6 +1061,8 @@
dev->name, dev->mtu, left, in_ntoa(iph->saddr)));
DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr)));
+ if (mtu < 8)
+ return;
/* Check for any "DF" flag. */
if (iph->frag_off & htons (IP_DF))
{
@@ -1060,11 +1071,6 @@
dev->name, dev->mtu, left, in_ntoa(iph->saddr)));
DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr)));
- /*
- * FIXME:
- * We should send an ICMP warning message here!
- */
-
icmp_send(skb,ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, dev);
return;
}
@@ -1077,15 +1083,6 @@
while(left > 0)
{
len = left;
-#ifdef OLD
- if (len+8 > mtu)
- len = (dev->mtu - hlen - 8);
- if ((left - len) >= 8)
- {
- len /= 8;
- len *= 8;
- }
-#else
/* IF: it doesn't fit, use 'mtu' - the data space left */
if (len > mtu)
len = mtu;
@@ -1096,7 +1093,6 @@
len/=8;
len*=8;
}
-#endif
DPRINTF((DBG_IP,"IP: frag: creating fragment of %d bytes (%d total)\n",
len, len + hlen));
@@ -1259,7 +1255,14 @@
kfree_skb(skb2,FREE_WRITE);
}
else
+ {
+ if(iph->tos & IPTOS_LOWDELAY)
+ dev2->queue_xmit(skb2, dev2, SOPRI_INTERACTIVE);
+ else if(iph->tos & IPTOS_THROUGHPUT)
+ dev2->queue_xmit(skb2, dev2, SOPRI_BACKGROUND);
+ else
dev2->queue_xmit(skb2, dev2, SOPRI_NORMAL);
+ }
}
}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/net/inet/skbuff.c linux-0.9pl4/net/inet/skbuff.c
--- linux-0.9pl3/net/inet/skbuff.c Thu Mar 10 14:15:09 1994
+++ linux-0.9pl4/net/inet/skbuff.c Mon Oct 10 16:48:38 1994
@@ -426,12 +426,14 @@
struct sk_buff *alloc_skb(unsigned int size,int priority)
{
struct sk_buff *skb;
- extern unsigned long intr_count;
if (intr_count && priority != GFP_ATOMIC) {
+ static int count = 0;
+ if (++count < 5) {
printk("alloc_skb called nonatomically from interrupt %08lx\n",
((unsigned long *)&size)[-1]);
priority = GFP_ATOMIC;
+ }
}
skb=(struct sk_buff *)kmalloc(size,priority);
if(skb==NULL)
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/net/inet/sock.c linux-0.9pl4/net/inet/sock.c
--- linux-0.9pl3/net/inet/sock.c Mon Sep 26 19:24:30 1994
+++ linux-0.9pl4/net/inet/sock.c Mon Oct 10 16:48:40 1994
@@ -428,7 +428,7 @@
* structure, otherwise we need to keep it around until
* everything is gone.
*/
- if (sk->rmem_alloc == 0 && sk->wmem_alloc == 0)
+ if (sk->dead && sk->rmem_alloc == 0 && sk->wmem_alloc == 0)
{
kfree_s((void *)sk,sizeof(*sk));
}
@@ -1194,8 +1194,12 @@
* We need to free it up because the tcp module creates
* it's own when it accepts one.
*/
- if (newsock->data) kfree_s(newsock->data, sizeof(struct sock));
+ if (newsock->data) {
+ struct sock * sk = (struct sock *) newsock->data;
newsock->data = NULL;
+ sk->dead = 1;
+ destroy_sock(sk);
+ }
if (sk1->prot->accept == NULL) return(-EOPNOTSUPP);
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/net/inet/tcp.c linux-0.9pl4/net/inet/tcp.c
--- linux-0.9pl3/net/inet/tcp.c Mon Sep 26 19:24:33 1994
+++ linux-0.9pl4/net/inet/tcp.c Mon Oct 10 16:48:43 1994
@@ -12,6 +12,9 @@
* Mark Evans, <evansmp@uhura.aston.ac.uk>
* Corey Minyard <wf-rch!minyard@relay.EU.net>
* Florian La Roche, <flla@stud.uni-sb.de>
+ * Charles Hedrick, <hedrick@klinzhai.rutgers.edu>
+ * Linus Torvalds, <torvalds@cs.helsinki.fi>
+ * Alan Cox, <gw4pts@gw4pts.ampr.org>
*
* Fixes:
* Alan Cox : Numerous verify_area() calls
@@ -63,6 +66,7 @@
* Charles Hedrick : Window fix
* Linus : Rewrote tcp_read() and URG handling
* completely
+ * Gerhard Koerting: Fixed some missing timer handling
*
*
* To Fix:
@@ -1548,8 +1552,13 @@
IPPROTO_TCP, sk->opt,
sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl);
if (tmp < 0) {
+ /* Finish anyway, treat this as a send that got lost. */
buff->free=1;
prot->wfree(sk,buff->mem_addr, buff->mem_len);
+ if(sk->state==TCP_ESTABLISHED)
+ sk->state=TCP_FIN_WAIT1;
+ else
+ sk->state=TCP_FIN_WAIT2;
release_sock(sk);
DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
return;
@@ -2085,6 +2094,13 @@
sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl);
if (tmp < 0) {
kfree_skb(buff,FREE_WRITE);
+ if(sk->state==TCP_ESTABLISHED)
+ sk->state=TCP_FIN_WAIT1;
+ else
+ sk->state=TCP_FIN_WAIT2;
+ reset_timer(sk, TIME_CLOSE,4*sk->rto);
+ if(timeout)
+ tcp_time_wait(sk);
DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
release_sock(sk);
return;
@@ -2915,6 +2931,7 @@
case TCP_SYN_SENT:
case TCP_ESTABLISHED:
/* Contains the one that needs to be acked */
+ reset_timer(sk, TIME_CLOSE, TCP_TIMEOUT_LEN);
sk->fin_seq = th->seq+1;
sk->state = TCP_CLOSE_WAIT;
if (th->rst) sk->shutdown = SHUTDOWN_MASK;
@@ -3447,6 +3464,15 @@
kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
+
+ case TCP_SYN_RECV:
+ if (th->syn) {
+ /* Probably a retransmitted syn */
+ kfree_skb(skb, FREE_READ);
+ release_sock(sk);
+ return(0);
+ }
+
default:
if (!tcp_sequence(sk, th, len, opt, saddr,dev)) {
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/tools/amiga/bootstrap.c linux-0.9pl4/tools/amiga/bootstrap.c
--- linux-0.9pl3/tools/amiga/bootstrap.c Thu Sep 29 18:19:15 1994
+++ linux-0.9pl4/tools/amiga/bootstrap.c Mon Nov 21 18:09:09 1994
@@ -2,12 +2,12 @@
** bootstrap.c -- This program loads the Linux/68k kernel into an Amiga
** and and launches it.
**
-** Copyright 1993 by Hamish Macdonald, Greg Harp
+** Copyright 1993,1994 by Hamish Macdonald, Greg Harp
**
** Modified 11-May-94 by Geert Uytterhoeven (uytterho@cs.kuleuven.ac.be)
** - A3640 MapROM check
** Modified 31-May-94 by Geert Uytterhoeven
-** - Memory thrash problem solved
+** - Memory trash problem solved
**
** This file is subject to the terms and conditions of the GNU General Public
** License. See the file README.legal in the main directory of this archive
@@ -48,6 +48,7 @@
struct GfxBase *GfxBase;
struct bootinfo bi;
+u_long bi_size = sizeof bi;
caddr_t CustomBase = (caddr_t)CUSTOM_PHYSADDR;
@@ -78,6 +79,7 @@
movel _start_mem,a5
movel _mem_size,d0
movel _rd_size,d1
+ movel _bi_size,d5
movel a3@(4),d2 | kexec.a_text
movel a3@(8),d3 | kexec.a_data
movel a3@(12),d4 | kexec.a_bss
@@ -104,12 +106,23 @@
bras 1b
2:
+ | /* copy bootinfo to end of bss */
+ movel a4,a1 | src = (u long *)memptr + kexec.a_text + kexec.a_data);
+ addl d2,a1
+ addl d3,a1 | dest = end of bss (already in a0)
+ movel d5,d7 | count = sizeof bi
+ subql #1,d7
+1: moveb a1@+,a0@+ | while (--count > -1)
+ dbra d7,1b | *dest++ = *src++
+
+
| /* copy the ramdisk to the top of memory (from back to front) */
movel a5,a1 | dest = (u_long *)(start_mem + mem_size);
addl d0,a1
- movel a4,a2 | limit = (u_long *)(memptr + kexec.a_text + kexec.a_data);
+ movel a4,a2 | limit = (u_long *)(memptr + kexec.a_text + kexec.a_data + sizeof bi);
addl d2,a2
addl d3,a2
+ addl d5,a2
movel a2,a0 | src = (u_long *)((u_long)limit + rd_size);
addl d1,a0
1: cmpl a0,a2
@@ -155,6 +168,7 @@
movel d7,d0
notl d0
movel d0,a0@
+ nop
cmpl a1@,d0
jnes 1f
/* MapROMmed A3640 present */
@@ -189,13 +203,12 @@
char *ramdisk_name = NULL;
char *memfile = NULL;
u_long memreq;
- struct nlist *nl;
void (*startfunc)(void);
long startcodesize;
- u_long *stack, kbi_offset;
+ u_long *stack, text_offset;
/* print the greet message */
- puts("Linux/68k Amiga Bootstrap version 1.9");
+ puts("Linux/68k Amiga Bootstrap version 1.10");
puts("Copyright 1993,1994 by Hamish Macdonald and Greg Harp\n");
/* machine is Amiga */
@@ -526,6 +539,27 @@
exit (EXIT_FAILURE);
}
+ switch (N_MAGIC(kexec)) {
+ case ZMAGIC:
+ text_offset = N_TXTOFF(kexec);
+ break;
+ case QMAGIC:
+ text_offset = sizeof(kexec);
+ /* the text size includes the exec header; remove this */
+ kexec.a_text -= sizeof(kexec);
+ break;
+ default:
+ fprintf (stderr, "Wrong magic number %lo in kernel header\n",
+ N_MAGIC(kexec));
+ exit (EXIT_FAILURE);
+ }
+
+ /* Load the kernel at one page after start of mem */
+ start_mem += PAGE_SIZE;
+ mem_size -= PAGE_SIZE;
+ /* Align bss size to multiple of four */
+ kexec.a_bss = (kexec.a_bss + 3) & ~3;
+
if (ramdisk_name) {
if ((rfd = open (ramdisk_name, O_RDONLY)) == -1) {
fprintf (stderr, "Unable to open ramdisk file %s\n",
@@ -540,22 +574,13 @@
rd_size = bi.ramdisk_size << 10;
bi.ramdisk_addr = (u_long)start_mem + mem_size - rd_size;
- /* find offset to boot_info structure */
- if (!(nl = get_nlist (kernel_name, "_boot_info"))) {
- perror ("get_nlist");
- exit (EXIT_FAILURE);
- } else {
- kbi_offset = nl->n_value - kexec.a_entry;
- free (nl);
- }
-
- memreq = kexec.a_text + kexec.a_data + rd_size;
+ memreq = kexec.a_text + kexec.a_data + sizeof(bi) + rd_size;
if (!(memptr = (char *)AllocMem (memreq, MEMF_FAST | MEMF_CLEAR))) {
fprintf (stderr, "Unable to allocate memory\n");
exit (EXIT_FAILURE);
}
- if (lseek (kfd, N_TXTOFF(kexec), L_SET) == -1) {
+ if (lseek (kfd, text_offset, L_SET) == -1) {
fprintf (stderr, "Failed to seek to text\n");
FreeMem ((void *)memptr, memreq);
exit (EXIT_FAILURE);
@@ -565,11 +590,8 @@
FreeMem ((void *)memptr, memreq);
exit (EXIT_FAILURE);
}
- if (lseek (kfd, N_DATOFF(kexec), L_SET) == -1) {
- fprintf (stderr, "Failed to seek to data\n");
- FreeMem ((void *)memptr, memreq);
- exit (EXIT_FAILURE);
- }
+
+ /* data follows immediately after text */
if (read (kfd, memptr + kexec.a_text, kexec.a_data) != kexec.a_data) {
fprintf (stderr, "Failed to read data\n");
FreeMem ((void *)memptr, memreq);
@@ -577,8 +599,9 @@
}
close (kfd);
- /* copy the boot_info struct to the kernel image */
- memcpy ((void *)(memptr + kbi_offset), &bi, sizeof(bi));
+ /* copy the boot_info struct to the end of the kernel image */
+ memcpy ((void *)(memptr + kexec.a_text + kexec.a_data), &bi,
+ sizeof(bi));
if (rfd != -1) {
if (lseek (rfd, 0, L_SET) == -1) {
@@ -586,8 +609,8 @@
FreeMem ((void *)memptr, memreq);
exit (EXIT_FAILURE);
}
- if (read (rfd, memptr + kexec.a_text + kexec.a_data,
- rd_size) != rd_size) {
+ if (read (rfd, memptr + kexec.a_text + kexec.a_data
+ + sizeof(bi), rd_size) != rd_size) {
fprintf (stderr, "Failed to read ramdisk file\n");
FreeMem ((void *)memptr, memreq);
exit (EXIT_FAILURE);
@@ -622,12 +645,15 @@
(u_long)memptr + kexec.a_text + kexec.a_data,
bi.ramdisk_size);
- printf ("\nKernel text at %#lx, code size %d\n",
- start_mem + N_TXTADDR(kexec), kexec.a_text);
- printf ("Kernel data at %#lx, data size %d\n",
- start_mem + N_DATADDR(kexec), kexec.a_data );
- printf ("Kernel bss at %#lx, bss size %d\n",
- start_mem + N_BSSADDR(kexec), kexec.a_bss );
+ printf ("\nKernel text at %#lx, code size %x\n",
+ start_mem, kexec.a_text);
+ printf ("Kernel data at %#lx, data size %x\n",
+ start_mem + kexec.a_text, kexec.a_data );
+ printf ("Kernel bss at %#lx, bss size %x\n",
+ start_mem + kexec.a_text + kexec.a_data,
+ kexec.a_bss );
+ printf ("boot info at %#lx\n", start_mem + kexec.a_text
+ + kexec.a_data + kexec.a_bss);
printf ("\nKernel entry is %#x\n", kexec.a_entry );
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/tools/amiga/bootstrap.h linux-0.9pl4/tools/amiga/bootstrap.h
--- linux-0.9pl3/tools/amiga/bootstrap.h Sun Aug 14 10:29:11 1994
+++ linux-0.9pl4/tools/amiga/bootstrap.h Sat Nov 12 12:40:13 1994
@@ -128,12 +128,6 @@
*/
#define GFXG_AGA (GFXF_AA_ALICE|GFXF_AA_LISA)
-/*
- * Get an nlist structure containing the information
- * for the given symbol from the given file.
- */
-extern struct nlist *get_nlist (const char *fname, const char *symname);
-
struct Library;
extern struct ExecBase *SysBase;
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/tools/amiga/get_nlist.c linux-0.9pl4/tools/amiga/get_nlist.c
--- linux-0.9pl3/tools/amiga/get_nlist.c Sun Aug 14 10:29:11 1994
+++ linux-0.9pl4/tools/amiga/get_nlist.c Wed Dec 31 19:00:00 1969
@@ -1,97 +0,0 @@
-/*
-** get_nlist.c -- This file contains the routines for getting a symbol
-** table entry when booting the Amiga Linux kernel.
-**
-** Copyright 1993 by Hamish Macdonald
-**
-** This file is subject to the terms and conditions of the GNU General Public
-** License. See the file README.legal in the main directory of this archive
-** for more details.
-**
-*/
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/fcntl.h>
-#include <unistd.h>
-#include <linux/a.out.h>
-
-struct nlist *get_nlist (const char *fname, const char *symname)
-{
- int fd = open (fname, O_RDONLY);
- struct exec ex;
- struct nlist *nl, *p = NULL, *syms;
- char *strs;
- off_t filesize;
- long strsize, numsyms;
-
- if (fd == -1)
- return NULL;
-
-#ifdef DEBUG
- printf ("fd is %d\n", fd);
-#endif
-
- read (fd, &ex, sizeof(ex));
- if (!ex.a_syms) {
- close (fd);
- return NULL;
- }
-
-#ifdef DEBUG
- printf ("%d bytes of symbol data\n", ex.a_syms);
-#endif
-
- syms = (struct nlist *)malloc (ex.a_syms);
- if (!syms) {
- close (fd);
- return NULL;
- }
- lseek (fd, N_SYMOFF(ex), L_SET);
- read (fd, syms, ex.a_syms);
- numsyms = ex.a_syms / sizeof (struct nlist);
-#ifdef DEBUG
- printf ("there are %d symbols\n", numsyms);
-#endif
-
- filesize = lseek (fd, 0L, L_XTND);
-#ifdef DEBUG
- printf ("there are %d characters in the file\n", filesize);
-#endif
- strsize = filesize - N_STROFF(ex);
-#ifdef DEBUG
- printf ("%d characters in the string table\n", strsize);
-#endif
-
- strs = (char *)malloc (strsize);
- if (!strs) {
- free (syms);
- close (fd);
- return NULL;
- }
- lseek (fd, N_STROFF(ex), L_SET);
- read (fd, strs, strsize);
-
- for (nl = syms; nl < syms + numsyms; nl++) {
-#ifdef DEBUG
- printf ("checking symbol number %d, name %s\n",
- nl - syms, strs + nl->n_un.n_strx);
-#endif
- if (strcmp (symname, strs + nl->n_un.n_strx) == 0
- && nl->n_type == N_BSS | N_EXT) {
- p = (struct nlist *)malloc (sizeof (struct nlist)
- + strlen(strs + nl->n_un.n_strx) + 1);
- if (!p)
- break;
- *p = *nl;
- p->n_un.n_name = (char *)(p+1);
- strcpy (p->n_un.n_name, strs + nl->n_un.n_strx);
- }
- }
-
- free (strs);
- free (syms);
- close (fd);
- return p;
-}
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/tools/atari/Makefile linux-0.9pl4/tools/atari/Makefile
--- linux-0.9pl3/tools/atari/Makefile Sun Aug 14 10:29:12 1994
+++ linux-0.9pl4/tools/atari/Makefile Thu Nov 24 21:11:00 1994
@@ -3,19 +3,10 @@
CFLAGS := -Wall -O2 -fno-defer-pop -mint -s
LD := d:/gnu/bin/gcc.ttp
LDFLAGS := -mint -D__GNUC__
-AS := d:/gnu/bin/gcc.ttp -c
-bootstra.ttp: boot_asm.o bootstra.o
+bootstra.ttp: bootstra.o
$(LD) $(LDFLAGS) -o $@ $^
prgflags 7 7 $@
cp $@ d:/linux
bootstra.o: bootstra.c bootinfo.h
-
-gen_nlis.o: gen_nlis.c
-
-boot_asm.o: boot_asm.S
-
-%.s: %.c
- $(CC) $(CFLAGS) -S $^ -o $@
-
diff -ubr -x RCS -x *.[ao] -x .depend -x .version -x .config -x System.map -x vmlinux -x bootstrap -x *~ -x config.old -x *.orig -x *.rej -x *# -x version.h -x autoconf.h --new-file linux-0.9pl3/tools/atari/bootstrap.c linux-0.9pl4/tools/atari/bootstrap.c
--- linux-0.9pl3/tools/atari/bootstrap.c Sun Aug 14 10:29:12 1994
+++ linux-0.9pl4/tools/atari/bootstrap.c Mon Nov 21 18:12:14 1994
@@ -8,6 +8,15 @@
** for more details.
**
** History:
+** 14 Nov 1994 YANML (Yet Another New Memory Layout :-) kernel
+** start address is KSTART_ADDR + PAGE_SIZE, this
+** does not need the ugly klugde with
+** -fwritable-strings (++andreas)
+** 09 Sep 1994 Adapted to the new memory layout: All the boot_info entry
+** mentions all ST-Ram and the mover is located somewhere
+** in the middle of memory (roman)
+** Added the default arguments file known from the other
+** bootstrap version
** 19 Feb 1994 Changed everything so that it works? (rdv)
** 14 Mar 1994 New mini-copy routine used (rdv)
*/
@@ -17,6 +26,7 @@
#include <unistd.h>
#include <stddef.h>
#include <string.h>
+#include <ctype.h>
#include "sysvars.h"
#include <osbind.h>
#include <sys/types.h>
@@ -34,7 +44,9 @@
extern char *optarg;
extern int optind;
-extern struct nlist *get_nlist(const char *fname, const char *symname);
+static void get_default_args( int *argc, char ***argv );
+/* This is missing in <unistd.h> */
+extern int sync (void);
struct bootinfo bi;
u_long *cookiejar;
@@ -92,50 +104,79 @@
subql #4,d0
jcc 1b
+ tstl d1
+ beq 3f
+
2: movel a3@-,a2@- /* copy the ramdisk starting at the end */
subql #4,d1
jcc 2b
- jmp a4@ /* jump to the start of the kernel */
+3: jmp a4@ /* jump to the start of the kernel */
_copyallend:
");
extern char copyall, copyallend;
-static void volatile boot_exit(int status)
+/* ++andreas: this must be inline due to Super */
+static inline void boot_exit (int) __attribute__ ((noreturn));
+static inline void boot_exit(int status)
{
/* first go back to user mode */
(void)Super(userstk);
+ getchar();
exit(status);
}
int main(int argc, char *argv[])
{
- int debugflag = 0, ch, kfd, rfd = -1, lang, i;
+ int debugflag = 0, ch, kfd, rfd = -1, i, ignore_ttram = 0;
+ int load_to_stram = 0;
+#if 0
+ int lang;
+#endif
char *ramdisk_name, *kernel_name, *memptr;
u_long ST_ramsize, TT_ramsize, memreq;
- u_long cpu_type, fpu_type, mch_type, mint, language;
- struct nlist *nl;
+ u_long cpu_type, fpu_type, mch_type, mint;
+#if 0
+ u_long language;
+#endif
struct exec kexec;
+#if 0
OSHEADER *os_header;
- u_long start_mem, mem_size, rd_size, kbi_offset;
+#endif
+ u_long start_mem, mem_size, rd_size, text_offset;
+#if 0
+ u_long mover_size;
+ void *mover_addr;
+#endif
ramdisk_name = NULL;
kernel_name = "vmlinux";
/* print the startup message */
- puts("\fLinux/68k Atari Bootstrap version 0.2");
- puts("Copyright 1993,1994 by Arjan Knor, Robert de Vries\n");
+ puts("\fLinux/68k Atari Bootstrap version 0.4");
+ puts("Copyright 1993,1994 by Arjan Knor, Robert de Vries, Roman Hodek, Andreas Schwab\n");
+
+ /* ++roman: If no arguments on the command line, read them from
+ * file */
+ if (argc == 1)
+ get_default_args( &argc, &argv );
/* machine is Atari */
bi.machtype = MACH_ATARI;
/* check arguments */
- while ((ch = getopt(argc, argv, "dk:r:")) != EOF)
+ while ((ch = getopt(argc, argv, "dtsk:r:")) != EOF)
switch (ch) {
case 'd':
debugflag = 1;
break;
+ case 't':
+ ignore_ttram = 1;
+ break;
+ case 's':
+ load_to_stram = 1;
+ break;
case 'k':
kernel_name = optarg;
break;
@@ -264,7 +305,8 @@
/* The size must be a multiple of 1MB. */
i = 0;
TT_ramsize = 0;
- if (mch_type == MACH_TT && *ramtop) {
+ if (!ignore_ttram &&
+ (mch_type == MACH_TT || mch_type == MACH_FALCON) && *ramtop) {
/* the 'ramtop' variable at 0x05a4 is not
* officially documented. We use it anyway
* because it is the only way to get the TTram size.
@@ -277,28 +319,31 @@
printf("TT-RAM: %ld Mb; ", TT_ramsize);
}
-
- bi.memory[i].addr = PAGE_SIZE; /* do not use the exception space
- (this comes down to the first page) */
- bi.memory[i].size = (*phystop - bi.memory[i].addr) & ~(MB - 1);
+ bi.memory[i].addr = 0;
+ bi.memory[i].size = *phystop & ~(MB - 1);
ST_ramsize = bi.memory[i].size / MB;
- bi.bi_atari.stram_start = bi.memory[i].addr + bi.memory[i].size;
- bi.bi_atari.stram_size = *phystop - bi.bi_atari.stram_start;
-
i++;
- printf("ST-RAM: %ld Mb; %ld Kb unmapped; ", ST_ramsize,
- bi.bi_atari.stram_size / 1024);
+ printf("ST-RAM: %ld Mb; ", ST_ramsize );
bi.num_memory = i;
+ if (load_to_stram && i > 1)
+ {
+ /* Put ST-RAM first in the list of mem blocks */
+ struct mem_info temp = bi.memory[i - 1];
+ bi.memory[i - 1] = bi.memory[0];
+ bi.memory[0] = temp;
+ }
+
/* verify that there is enough RAM; ST- and TT-RAM combined */
if (ST_ramsize + TT_ramsize < MIN_RAMSIZE) {
puts("Not enough RAM. Aborting...");
boot_exit(10);
}
+#if 0
/* Get language/keyboard info */
/* TODO: do we need this ? */
/* Could be used to auto-select keyboard map later on. (rdv) */
@@ -354,6 +399,7 @@
}
printf("\n");
}
+#endif
/*
* Copy command line options into the kernel command line.
@@ -394,6 +440,27 @@
boot_exit (EXIT_FAILURE);
}
+ switch (N_MAGIC(kexec)) {
+ case ZMAGIC:
+ text_offset = N_TXTOFF(kexec);
+ break;
+ case QMAGIC:
+ text_offset = sizeof(kexec);
+ /* the text size includes the exec header; remove this */
+ kexec.a_text -= sizeof(kexec);
+ break;
+ default:
+ fprintf (stderr, "Wrong magic number %lo in kernel header\n",
+ N_MAGIC(kexec));
+ boot_exit (EXIT_FAILURE);
+ }
+
+ /* Load the kernel one page after start of mem */
+ start_mem += PAGE_SIZE;
+ mem_size -= PAGE_SIZE;
+ /* Align bss size to multiple of four */
+ kexec.a_bss = (kexec.a_bss + 3) & ~3;
+
/* init ramdisk */
if(ramdisk_name) {
if((rfd = open(ramdisk_name, O_RDONLY)) == -1) {
@@ -409,23 +476,55 @@
rd_size = bi.ramdisk_size << 10;
bi.ramdisk_addr = (u_long)start_mem + mem_size - rd_size;
- /* find offset to boot_info structure */
- if (!(nl = get_nlist (kernel_name, "_boot_info")))
- {
- perror ("get_nlist");
- boot_exit (EXIT_FAILURE);
- }
+ /* calculate the total required amount of memory */
+ memreq = kexec.a_text + kexec.a_data + kexec.a_bss + sizeof (bi) + rd_size;
- kbi_offset = nl->n_value - kexec.a_entry;
- free (nl);
+ /* ++andreas: This not needed any more, left in for reference :-) */
+#if 0
- /* calculate the total required amount of memory */
- memreq = kexec.a_text + kexec.a_data + kexec.a_bss + rd_size;
+ /* Allocate memory for the mover routine. It has to be disjunct
+ * from all three other areas, the kernel destination, the ramdisk
+ * destination and the load buffer for both. Because the mover
+ * space is allocated separately from the load buffer, it cannot
+ * overlap that one.
+ * To get some appropriate memory for the mover, the following
+ * steps are tried:
+ * - Leave it where it is (in bootstrap's code space)
+ * - If the kernel will go into TT-Ram, allocate memory from the ST-Ram
+ * - Allocate some memory before allocating the load buffer.
+ * - Allocate some memory after the load buffer
+ * - If all that failed, it is unlikely to find a suitable place.
+ * But to be sure, memory is alloced in bigger steps (32K)
+ * until there is no memory left.
+ */
+#define IS_DISJUNCT(a1,s1,a2,s2) ( (a2) > (a1)+(s1) || (a2)+(s2) < (a1) )
+#define MOVER_DISJUNCT(addr) \
+ (IS_DISJUNCT( start_mem, kexec.a_text+kexec.a_data+kexec.a_bss, \
+ (unsigned long)(addr), mover_size ) && \
+ IS_DISJUNCT( start_mem + mem_size - rd_size, rd_size, \
+ (unsigned long)(addr), mover_size ))
+
+ mover_size = ©allend - ©all;
+ mover_addr = ©all;
+
+ if (!MOVER_DISJUNCT(mover_addr) && TT_ramsize) {
+ /* If there is TT-Ram, try to put the mover into ST-Ram */
+ unsigned long addr;
+ addr = Mxalloc( mover_size, 0 );
+ if ((signed long)addr > 0) mover_addr = addr;
+ }
+ if (!MOVER_DISJUNCT(mover_addr)) {
+ if (!(mover_addr = (void *)Malloc( mover_size ))) {
+ fprintf( stderr, "Unable to allocate memory for mover code\n" );
+ boot_exit( EXIT_FAILURE );
+ }
+ }
+#endif
/* allocate RAM for the kernel */
if (!(memptr = (char *)Malloc (memreq)))
{
- fprintf (stderr, "Unable to allocate memory\n");
+ fprintf (stderr, "Unable to allocate memory for kernel and ramdisk\n");
boot_exit (EXIT_FAILURE);
}
else
@@ -433,8 +532,18 @@
(void)memset(memptr, 0, memreq);
+#if 0
+ while( !MOVER_DISJUNCT(mover_addr) ) {
+ if (!(mover_addr = (void *)Malloc( mover_size ))) {
+ fprintf( stderr, "Unable to allocate memory for mover code\n" );
+ boot_exit( EXIT_FAILURE );
+ }
+ (void)Malloc( 32*1024 );
+ }
+#endif
+
/* read the text and data segments from the kernel image */
- if (lseek (kfd, N_TXTOFF(kexec), SEEK_SET) == -1)
+ if (lseek (kfd, text_offset, SEEK_SET) == -1)
{
fprintf (stderr, "Failed to seek to text\n");
Mfree ((void *)memptr);
@@ -446,12 +555,8 @@
Mfree ((void *)memptr);
boot_exit (EXIT_FAILURE);
}
- if (lseek (kfd, N_DATOFF(kexec), SEEK_SET) == -1)
- {
- fprintf (stderr, "Failed to seek to data\n");
- Mfree ((void *)memptr);
- boot_exit (EXIT_FAILURE);
- }
+
+ /* data follows immediately after text */
if (read (kfd, memptr + kexec.a_text, kexec.a_data) != kexec.a_data)
{
fprintf (stderr, "Failed to read data\n");
@@ -460,8 +565,9 @@
}
close (kfd);
- /* copy the boot_info struct to the kernel image */
- memcpy ((void *)(memptr + kbi_offset), &bi, sizeof(bi));
+ /* copy the boot_info struct to the end of the kernel image */
+ memcpy ((void *)(memptr + kexec.a_text + kexec.a_data + kexec.a_bss),
+ &bi, sizeof(bi));
/* read the ramdisk image */
if (rfd != -1)
@@ -472,7 +578,7 @@
Mfree ((void *)memptr);
boot_exit (EXIT_FAILURE);
}
- if (read (rfd, memptr + kexec.a_text + kexec.a_data + kexec.a_bss,
+ if (read (rfd, memptr + kexec.a_text + kexec.a_data + kexec.a_bss + sizeof (bi),
rd_size) != rd_size)
{
fprintf (stderr, "Failed to read ramdisk file\n");
@@ -491,13 +597,13 @@
bi.ramdisk_size);
printf ("\nKernel text at %#lx, code size %d\n",
- start_mem + N_TXTADDR(kexec), kexec.a_text);
+ start_mem, kexec.a_text);
printf ("Kernel data at %#lx, data size %d\n",
- start_mem + N_DATADDR(kexec), kexec.a_data );
+ start_mem + kexec.a_text, kexec.a_data );
printf ("Kernel bss at %#lx, bss size %d\n",
- start_mem + N_BSSADDR(kexec), kexec.a_bss );
- printf ("\nKernel boot_info is at %#lx physical, %#lx virtual\n",
- start_mem + kbi_offset, kexec.a_entry + kbi_offset);
+ start_mem + kexec.a_text + kexec.a_data, kexec.a_bss );
+ printf ("\nboot_info is at %#lx\n",
+ start_mem + kexec.a_text + kexec.a_data + kexec.a_bss);
printf ("\nKernel entry is %#x\n", kexec.a_entry );
printf ("ramdisk dest top is %#lx\n", start_mem + mem_size);
printf ("ramdisk lower limit is %#lx\n",
@@ -505,6 +611,11 @@
printf ("ramdisk src top is %#lx\n",
(u_long)(memptr + kexec.a_text + kexec.a_data + kexec.a_bss) +
rd_size);
+#if 0
+ printf ("mover code resides from %#lx to %#lx\n",
+ (unsigned long)mover_addr,
+ (unsigned long)mover_addr + mover_size - 1 );
+#endif
printf ("Type a key to continue the Linux boot...");
fflush (stdout);
@@ -524,11 +635,20 @@
/* ..and any MMU translation */
disable_mmu();
- /* copy mover code to a safe place */
- memcpy((void*)0x400, ©all, ©allend - ©all);
+ /* copy mover code to a safe place if needed */
+#if 0
+ if (mover_addr != ©all)
+ memcpy( mover_addr, ©all, mover_size );
+#else
+ memcpy ((void *) 0x400, ©all, ©allend - ©all);
+#endif
/* setup stack */
- change_stack((void*)PAGE_SIZE);
+#if 0
+ change_stack( start_mem ? PAGE_SIZE : (void*)start_mem+mem_size-rd_size-8);
+#else
+ change_stack ((void *) PAGE_SIZE);
+#endif
/*
* On the Atari you can have two situations:
@@ -547,12 +667,87 @@
* This is more than enough for the miniscule mover routine (16 bytes).
*/
+#if 0
+ /* New copy scheme for new memory layout: The first 8 kernel bytes
+ * are nop's that needn't be copied. This avoids accessing the ROM
+ * bytes at the start of ST-Ram if the kernel will go there. The
+ * first arguement is the kernel start address, too.
+ * The mover code was copied to a place disjunct from any of the
+ * destination areas.
+ */
+
+ jump_to_mover((char *) start_mem + 8, memptr + 8,
+ (char *) start_mem + mem_size, memptr + memreq,
+ kexec.a_text + kexec.a_data + kexec.a_bss - 8,
+ rd_size,
+ mover_addr );
+#else
jump_to_mover((char *) start_mem, memptr,
(char *) start_mem + mem_size, memptr + memreq,
- kexec.a_text + kexec.a_data + kexec.a_bss,
+ kexec.a_text + kexec.a_data + kexec.a_bss + sizeof (bi),
rd_size,
- (void*)0x400);
+ (void *) 0x400);
+#endif
for (;;);
/* NOTREACHED */
}
+
+
+
+#define MAXARGS 30
+
+static void get_default_args( int *argc, char ***argv )
+
+{ FILE *f;
+ static char *nargv[MAXARGS];
+ char arg[256], *p;
+ int c, quote, state;
+
+ if (!(f = fopen( "bootargs", "r" )))
+ return;
+
+ *argc = 1;
+ if (***argv)
+ nargv[0] = **argv;
+ else
+ nargv[0] = "bootstrap";
+ *argv = nargv;
+
+ quote = state = 0;
+ p = arg;
+ while( (c = fgetc(f)) != EOF ) {
+
+ if (state == 0) {
+ /* outside args, skip whitespace */
+ if (!isspace(c)) {
+ state = 1;
+ p = arg;
+ }
+ }
+
+ if (state) {
+ /* inside an arg: copy it into 'arg', obeying quoting */
+ if (!quote && (c == '\'' || c == '"'))
+ quote = c;
+ else if (quote && c == quote)
+ quote = 0;
+ else if (!quote && isspace(c)) {
+ /* end of this arg */
+ *p = 0;
+ nargv[(*argc)++] = strdup(arg);
+ state = 0;
+ }
+ else
+ *p++ = c;
+ }
+ }
+ if (state) {
+ /* last arg finished by EOF! */
+ *p = 0;
+ nargv[(*argc)++] = strdup(arg);
+ }
+ fclose( f );
+
+ nargv[*argc] = 0;
+}